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
  • zyad-ayad/vlc
  • shocknovaa/vlc
  • gremlinflat/vlc
  • Pratham24D/vlc
  • hmaarrfk/vlc
412 results
Show changes
Commits on Source (11)
......@@ -83,13 +83,19 @@ struct frame_info_t
picture_t *p_picture;
int i_poc;
int i_foc;
vlc_tick_t pts;
vlc_tick_t dts;
unsigned field_rate_num;
unsigned field_rate_den;
bool b_flush;
bool b_eos;
bool b_keyframe;
bool b_leading;
bool b_field;
bool b_progressive;
bool b_top_field_first;
uint8_t i_num_ts;
uint8_t i_max_reorder;
unsigned i_length;
frame_info_t *p_next;
};
......@@ -99,6 +105,9 @@ struct frame_info_t
#define H264_MAX_DPB 16
#define VT_MAX_SEI_COUNT 16
#define DEFAULT_FRAME_RATE_NUM 30000
#define DEFAULT_FRAME_RATE_DEN 1001
typedef struct decoder_sys_t
{
CMVideoCodecType codec;
......@@ -120,16 +129,28 @@ typedef struct decoder_sys_t
/* !Codec specific callbacks */
bool b_vt_feed;
bool b_vt_flush;
bool b_vt_need_keyframe;
enum
{
STATE_BITSTREAM_WAITING_RAP = -2,
STATE_BITSTREAM_DISCARD_LEADING = -1,
STATE_BITSTREAM_SYNCED = 0,
} sync_state, start_sync_state;
enum
{
STATE_DECODER_WAITING_RAP = 0,
STATE_DECODER_STARTED,
} decoder_state;
VTDecompressionSessionRef session;
CMVideoFormatDescriptionRef videoFormatDescription;
/* Decoder Callback Synchronization */
vlc_mutex_t lock;
bool b_discard_decoder_output;
frame_info_t *p_pic_reorder;
uint8_t i_pic_reorder;
uint8_t i_pic_reorder_max;
bool b_strict_reorder;
bool b_invalid_pic_reorder_max;
bool b_poc_based_reorder;
......@@ -142,7 +163,6 @@ typedef struct decoder_sys_t
h264_poc_context_t h264_pocctx;
hevc_poc_ctx_t hevc_pocctx;
bool b_drop_blocks;
date_t pts;
vlc_video_context *vctx;
......@@ -150,16 +170,79 @@ typedef struct decoder_sys_t
} decoder_sys_t;
/* Picture pacer to work-around the VT session allocating too much CVPX buffers
* that can lead to a OOM. cf. pic_pacer_Wait usage in DecoderCallback() */
* that can lead to a OOM. */
struct pic_pacer
{
vlc_mutex_t lock;
vlc_cond_t wait;
uint8_t nb_field_out;
uint8_t field_reorder_max;
uint8_t nb_out;
uint8_t allocated_max;
uint8_t allocated_next;
uint8_t queued_for_decode;
};
static void pic_pacer_UpdateReorderMax(struct pic_pacer *, uint8_t, uint8_t);
#define PIC_PACER_ALLOCATABLE_MAX (1 /* callback, pre-reorder */ \
+ 2 /* filters */ \
+ 1 /* display */ \
+ 1 /* next/prev display */)
#define PIC_PACER_DECODE_QUEUE 4 /* max async decode before callback */
//#define PIC_PACER_DEBUG
static void pic_pacer_UpdateReorderMax(struct pic_pacer *, uint8_t);
static void pic_pacer_Destroy(void *priv)
{
(void) priv;
}
static void pic_pacer_Init(struct pic_pacer *pic_pacer)
{
vlc_mutex_init(&pic_pacer->lock);
vlc_cond_init(&pic_pacer->wait);
pic_pacer->nb_out = 0;
pic_pacer->allocated_max = 6;
pic_pacer->allocated_next = pic_pacer->allocated_max;
pic_pacer->queued_for_decode = 0;
}
static void pic_pacer_AccountAllocation(struct pic_pacer *pic_pacer)
{
vlc_mutex_lock(&pic_pacer->lock);
pic_pacer->nb_out += 1;
vlc_mutex_unlock(&pic_pacer->lock);
}
static void pic_pacer_AccountScheduledDecode(struct pic_pacer *pic_pacer)
{
vlc_mutex_lock(&pic_pacer->lock);
pic_pacer->queued_for_decode += 1;
vlc_mutex_unlock(&pic_pacer->lock);
}
static void pic_pacer_AccountFinishedDecode(struct pic_pacer *pic_pacer)
{
vlc_mutex_lock(&pic_pacer->lock);
pic_pacer->queued_for_decode -= 1;
vlc_cond_signal(&pic_pacer->wait);
vlc_mutex_unlock(&pic_pacer->lock);
}
static void pic_pacer_WaitAllocatableSlot(struct pic_pacer *pic_pacer)
{
vlc_mutex_lock(&pic_pacer->lock);
uint8_t allocatable_total = pic_pacer->allocated_max + PIC_PACER_DECODE_QUEUE;
while( pic_pacer->queued_for_decode + pic_pacer->nb_out >= allocatable_total )
{
#ifdef PIC_PACER_DEBUG
fprintf(stderr, "input pacing %d+%d >= %d\n",
pic_pacer->queued_for_decode, pic_pacer->nb_out, allocatable_total);
#endif
vlc_cond_wait(&pic_pacer->wait, &pic_pacer->lock);
/*update*/
allocatable_total = pic_pacer->allocated_max + PIC_PACER_DECODE_QUEUE;
}
vlc_mutex_unlock(&pic_pacer->lock);
}
#pragma mark - start & stop
......@@ -297,32 +380,18 @@ static bool FillReorderInfoH264(decoder_t *p_dec, const block_t *p_block,
p_info->i_num_ts = h264_get_num_ts(p_sps, &slice, sei.i_pic_struct,
p_info->i_foc, bFOC);
unsigned dummy;
h264_get_dpb_values(p_sps, &p_info->i_max_reorder, &dummy);
if (!p_info->b_progressive)
p_info->b_top_field_first = (sei.i_pic_struct % 2 == 1);
/* Set frame rate for timings in case of missing rate */
if ( (!p_dec->fmt_in->video.i_frame_rate_base ||
!p_dec->fmt_in->video.i_frame_rate) &&
p_sps->vui.i_time_scale && p_sps->vui.i_num_units_in_tick )
if (p_sps->vui.i_time_scale && p_sps->vui.i_num_units_in_tick)
{
date_Change( &p_sys->pts, p_sps->vui.i_time_scale,
p_sps->vui.i_num_units_in_tick );
p_info->field_rate_num = p_sps->vui.i_time_scale;
p_info->field_rate_den = p_sps->vui.i_num_units_in_tick;
}
if(!p_sys->b_invalid_pic_reorder_max && i_nal_type == H264_NAL_SLICE_IDR)
{
unsigned dummy;
uint8_t i_reorder;
h264_get_dpb_values(p_sps, &i_reorder, &dummy);
vlc_mutex_lock(&p_sys->lock);
p_sys->i_pic_reorder_max = i_reorder;
pic_pacer_UpdateReorderMax(p_sys->pic_pacer,
p_sys->i_pic_reorder_max,
p_info->i_num_ts);
vlc_mutex_unlock(&p_sys->lock);
}
}
return true; /* No need to parse further NAL */
......@@ -625,27 +694,6 @@ static bool FillReorderInfoHEVC(decoder_t *p_dec, const block_t *p_block,
if (!p_sli)
return false;
/* XXX: Work-around a VT bug on recent devices (iPhone X, MacBook
* Pro 2017). The VT session will report a BadDataErr if you send a
* RASL frame just after a CRA one. Indeed, RASL frames are
* corrupted if the decoding start at an IRAP frame (IDR/CRA), VT
* is likely failing to handle this case. */
if (!p_sys->b_vt_feed && (i_nal_type != HEVC_NAL_IDR_W_RADL &&
i_nal_type != HEVC_NAL_IDR_N_LP))
p_sys->b_drop_blocks = true;
else if (p_sys->b_drop_blocks)
{
if (i_nal_type == HEVC_NAL_RASL_N || i_nal_type == HEVC_NAL_RASL_R)
{
hevc_rbsp_release_slice_header(p_sli);
return false;
}
else
{
p_sys->b_drop_blocks = false;
}
}
p_info->b_keyframe = i_nal_type >= HEVC_NAL_BLA_W_LP;
enum hevc_slice_type_e slice_type;
if (hevc_get_slice_type(p_sli, &slice_type))
......@@ -673,34 +721,30 @@ static bool FillReorderInfoHEVC(decoder_t *p_dec, const block_t *p_block,
p_info->i_poc = POC;
p_info->i_foc = POC; /* clearly looks wrong :/ */
p_info->i_num_ts = hevc_get_num_clock_ts(p_sps, sei.p_timing);
p_info->b_flush = (POC == 0);
p_info->i_max_reorder = hevc_get_max_num_reorder(p_vps);
p_info->b_flush = (POC == 0) ||
(i_nal_type >= HEVC_NAL_IDR_N_LP &&
i_nal_type <= HEVC_NAL_IRAP_VCL23);
p_info->b_field = (p_info->i_num_ts == 1);
p_info->b_progressive = hevc_frame_is_progressive(p_sps, sei.p_timing);
/* Set frame rate for timings in case of missing rate */
if ( (!p_dec->fmt_in->video.i_frame_rate_base ||
!p_dec->fmt_in->video.i_frame_rate) )
{
unsigned num, den;
if (hevc_get_frame_rate(p_sps, p_vps, &num, &den))
date_Change(&p_sys->pts, num, den);
}
if(hevc_get_frame_rate(p_sps, p_vps, &p_info->field_rate_num,
&p_info->field_rate_den))
p_info->field_rate_num *= 2;
if (sei.p_timing)
hevc_release_sei_pic_timing(sei.p_timing);
if (!p_sys->b_invalid_pic_reorder_max && p_vps)
{
vlc_mutex_lock(&p_sys->lock);
p_sys->i_pic_reorder_max = hevc_get_max_num_reorder(p_vps);
pic_pacer_UpdateReorderMax(p_sys->pic_pacer,
p_sys->i_pic_reorder_max,
p_info->i_num_ts);
vlc_mutex_unlock(&p_sys->lock);
}
}
/* RASL Open GOP */
/* XXX: Work-around a VT bug on recent devices (iPhone X, MacBook
* Pro 2017). The VT session will report a BadDataErr if you send a
* RASL frame just after a CRA one. Indeed, RASL frames are
* corrupted if the decoding start at an IRAP frame (IDR/CRA), VT
* is likely failing to handle this case. */
p_info->b_leading = ( i_nal_type == HEVC_NAL_RASL_N || i_nal_type == HEVC_NAL_RASL_R );
hevc_rbsp_release_slice_header(p_sli);
return true; /* No need to parse further NAL */
}
......@@ -784,7 +828,7 @@ static void InsertIntoDPB(decoder_sys_t *p_sys, frame_info_t *p_info)
else if (p_sys->b_poc_based_reorder)
b_insert = ((*pp_lead_in)->i_foc > p_info->i_foc);
else
b_insert = ((*pp_lead_in)->p_picture->date >= p_info->p_picture->date);
b_insert = ((*pp_lead_in)->pts >= p_info->pts);
if (b_insert)
{
......@@ -801,36 +845,61 @@ static void InsertIntoDPB(decoder_sys_t *p_sys, frame_info_t *p_info)
#endif
}
static picture_t * RemoveOneFrameFromDPB(decoder_sys_t *p_sys)
static int RemoveOneFrameFromDPB(decoder_sys_t *p_sys, picture_t **pp_ret)
{
frame_info_t *p_info = p_sys->p_pic_reorder;
if (p_info == NULL)
return NULL;
{
*pp_ret = NULL;
return VLC_EGENERIC;
}
const int i_framepoc = p_info->i_poc;
const vlc_tick_t i_framepts = p_info->pts;
picture_t *p_ret = NULL;
picture_t **pp_ret_last = &p_ret;
picture_t **pp_ret_last = pp_ret;
bool b_dequeue;
do
{
picture_t *p_field = p_info->p_picture;
/* Asynchronous fallback time init */
if(date_Get(&p_sys->pts) == VLC_TICK_INVALID)
{
date_Set(&p_sys->pts, p_info->pts != VLC_TICK_INVALID ?
p_info->pts : p_info->dts );
}
/* Compute time if missing */
if (p_field->date == VLC_TICK_INVALID)
p_field->date = date_Get(&p_sys->pts);
/* Compute time from output if missing */
if (p_info->pts == VLC_TICK_INVALID)
p_info->pts = date_Get(&p_sys->pts);
else
date_Set(&p_sys->pts, p_field->date);
date_Set(&p_sys->pts, p_info->pts);
/* Update frame rate (used on interpolation) */
if(p_info->field_rate_num != p_sys->pts.i_divider_num ||
p_info->field_rate_den != p_sys->pts.i_divider_den)
{
/* no date_Change due to possible invalid num */
date_Init(&p_sys->pts, p_info->field_rate_num,
p_info->field_rate_den);
date_Set(&p_sys->pts, p_info->pts);
}
/* Set next picture time, in case it is missing */
if (p_info->i_length)
date_Set(&p_sys->pts, p_field->date + p_info->i_length);
date_Set(&p_sys->pts, p_info->pts + p_info->i_length);
else
date_Increment(&p_sys->pts, p_info->i_num_ts);
*pp_ret_last = p_field;
pp_ret_last = &p_field->p_next;
if( p_info->p_picture ) /* Can have no picture attached to entry on error */
{
if( p_info->p_picture->date == VLC_TICK_INVALID )
p_info->p_picture->date = p_info->pts;
/* Extract attached field to output list */
*pp_ret_last = p_info->p_picture;
pp_ret_last = &p_info->p_picture->p_next;
}
p_sys->i_pic_reorder--;
......@@ -843,7 +912,7 @@ static picture_t * RemoveOneFrameFromDPB(decoder_sys_t *p_sys)
if (p_sys->b_poc_based_reorder)
b_dequeue = (p_info->i_poc == i_framepoc);
else
b_dequeue = (p_field->date == p_info->p_picture->date);
b_dequeue = (p_info->pts == i_framepts);
}
else
{
......@@ -852,7 +921,7 @@ static picture_t * RemoveOneFrameFromDPB(decoder_sys_t *p_sys)
} while(b_dequeue);
return p_ret;
return VLC_SUCCESS;
}
static void DrainDPBLocked(decoder_t *p_dec, bool flush)
......@@ -860,10 +929,10 @@ static void DrainDPBLocked(decoder_t *p_dec, bool flush)
decoder_sys_t *p_sys = p_dec->p_sys;
for ( ;; )
{
picture_t *p_fields = RemoveOneFrameFromDPB(p_sys);
if (p_fields == NULL)
picture_t *p_fields;
if(RemoveOneFrameFromDPB(p_sys, &p_fields) != VLC_SUCCESS)
break;
do
for ( ; p_fields; )
{
picture_t *p_next = p_fields->p_next;
p_fields->p_next = NULL;
......@@ -872,7 +941,7 @@ static void DrainDPBLocked(decoder_t *p_dec, bool flush)
else
decoder_QueueVideo(p_dec, p_fields);
p_fields = p_next;
} while(p_fields != NULL);
}
}
}
......@@ -899,59 +968,74 @@ static frame_info_t * CreateReorderInfo(decoder_t *p_dec, const block_t *p_block
p_info->b_keyframe = true;
}
p_info->dts = p_block->i_dts;
p_info->pts = p_block->i_pts;
p_info->i_length = p_block->i_length;
if(p_dec->fmt_in->video.i_frame_rate && p_dec->fmt_in->video.i_frame_rate_base) /* demux forced rate */
{
p_info->field_rate_num = p_dec->fmt_in->video.i_frame_rate * 2;
p_info->field_rate_den = p_dec->fmt_in->video.i_frame_rate_base;
}
else if(!p_info->field_rate_num || !p_info->field_rate_den) /* full fallback */
{
p_info->field_rate_num = DEFAULT_FRAME_RATE_NUM * 2;
p_info->field_rate_den = DEFAULT_FRAME_RATE_DEN;
}
/* required for still pictures/menus */
p_info->b_eos = (p_block->i_flags & BLOCK_FLAG_END_OF_SEQUENCE);
if (date_Get(&p_sys->pts) == VLC_TICK_INVALID)
date_Set(&p_sys->pts, p_block->i_dts);
return p_info;
}
static void OnDecodedFrame(decoder_t *p_dec, frame_info_t *p_info)
{
decoder_sys_t *p_sys = p_dec->p_sys;
assert(p_info->p_picture);
if(!p_sys->b_invalid_pic_reorder_max &&
p_info->i_max_reorder != p_sys->i_pic_reorder_max)
{
p_sys->i_pic_reorder_max = p_info->i_max_reorder;
pic_pacer_UpdateReorderMax(p_sys->pic_pacer, p_sys->i_pic_reorder_max);
}
while(p_info->b_flush || p_sys->i_pic_reorder >= p_sys->i_pic_reorder_max)
{
/* First check if DPB sizing was correct before removing one frame */
if (p_sys->p_pic_reorder && !p_info->b_flush &&
if (p_sys->p_pic_reorder && !p_sys->b_strict_reorder && !p_info->b_flush &&
p_sys->i_pic_reorder_max < H264_MAX_DPB)
{
if (p_sys->b_poc_based_reorder && p_sys->p_pic_reorder->i_foc > p_info->i_foc)
{
p_sys->b_invalid_pic_reorder_max = true;
p_sys->i_pic_reorder_max++;
pic_pacer_UpdateReorderMax(p_sys->pic_pacer,
p_sys->i_pic_reorder_max, p_info->i_num_ts);
pic_pacer_UpdateReorderMax(p_sys->pic_pacer, p_sys->i_pic_reorder_max);
msg_Dbg(p_dec, "Raising max DPB to %"PRIu8, p_sys->i_pic_reorder_max);
break;
}
else if (!p_sys->b_poc_based_reorder &&
p_info->p_picture->date > VLC_TICK_INVALID &&
p_sys->p_pic_reorder->p_picture->date > p_info->p_picture->date)
p_info->pts > VLC_TICK_INVALID &&
p_sys->p_pic_reorder->pts > p_info->pts)
{
p_sys->b_invalid_pic_reorder_max = true;
p_sys->i_pic_reorder_max++;
pic_pacer_UpdateReorderMax(p_sys->pic_pacer,
p_sys->i_pic_reorder_max, p_info->i_num_ts);
pic_pacer_UpdateReorderMax(p_sys->pic_pacer, p_sys->i_pic_reorder_max);
msg_Dbg(p_dec, "Raising max DPB to %"PRIu8, p_sys->i_pic_reorder_max);
break;
}
}
picture_t *p_fields = RemoveOneFrameFromDPB(p_sys);
if (p_fields == NULL)
picture_t *p_fields;
if(RemoveOneFrameFromDPB(p_sys, &p_fields) != VLC_SUCCESS)
break;
do
for(; p_fields;)
{
picture_t *p_next = p_fields->p_next;
p_fields->p_next = NULL;
decoder_QueueVideo(p_dec, p_fields);
p_fields = p_next;
} while(p_fields != NULL);
}
}
InsertIntoDPB(p_sys, p_info);
......@@ -1132,21 +1216,6 @@ static CFMutableDictionaryRef CreateSessionDescriptionFormat(decoder_t *p_dec,
return decoderConfiguration;
}
static void PtsInit(decoder_t *p_dec)
{
decoder_sys_t *p_sys = p_dec->p_sys;
if (p_dec->fmt_in->video.i_frame_rate_base && p_dec->fmt_in->video.i_frame_rate)
{
date_Init(&p_sys->pts, p_dec->fmt_in->video.i_frame_rate * 2,
p_dec->fmt_in->video.i_frame_rate_base);
}
else
{
date_Init(&p_sys->pts, 2 * 30000, 1001);
}
}
static int StartVideoToolbox(decoder_t *p_dec)
{
decoder_sys_t *p_sys = p_dec->p_sys;
......@@ -1268,25 +1337,12 @@ static void StopVideoToolbox(decoder_t *p_dec)
CFRelease(p_sys->videoFormatDescription);
p_sys->videoFormatDescription = NULL;
}
p_sys->b_vt_feed = false;
p_sys->b_drop_blocks = false;
p_sys->sync_state = p_sys->start_sync_state;
p_sys->decoder_state = STATE_DECODER_WAITING_RAP;
}
#pragma mark - module open and close
static void pic_pacer_Destroy(void *priv)
{
(void) priv;
}
static void pic_pacer_Init(struct pic_pacer *pic_pacer, uint8_t pic_reorder_max)
{
vlc_mutex_init(&pic_pacer->lock);
vlc_cond_init(&pic_pacer->wait);
pic_pacer->nb_field_out = 0;
pic_pacer->field_reorder_max = pic_reorder_max * 2;
}
static int
CreateVideoContext(decoder_t *p_dec)
{
......@@ -1320,7 +1376,7 @@ CreateVideoContext(decoder_t *p_dec)
CVPX_VIDEO_CONTEXT_VIDEOTOOLBOX);
assert(p_sys->pic_pacer);
pic_pacer_Init(p_sys->pic_pacer, p_sys->i_pic_reorder_max);
pic_pacer_Init(p_sys->pic_pacer);
return VLC_SUCCESS;
}
......@@ -1369,6 +1425,9 @@ static int OpenDecoder(vlc_object_t *p_this)
p_sys->i_pic_reorder_max = 4;
p_sys->vtsession_status = VTSESSION_STATUS_OK;
p_sys->b_cvpx_format_forced = false;
/* will be fixed later */
date_Init(&p_sys->pts, p_dec->fmt_in->video.i_frame_rate,
p_dec->fmt_in->video.i_frame_rate_base);
char *cvpx_chroma = var_InheritString(p_dec, "videotoolbox-cvpx-chroma");
if (cvpx_chroma != NULL)
......@@ -1402,8 +1461,6 @@ static int OpenDecoder(vlc_object_t *p_this)
return i_ret;
}
p_sys->b_vt_need_keyframe = false;
vlc_mutex_init(&p_sys->lock);
p_dec->pf_decode = DecodeBlock;
......@@ -1421,8 +1478,9 @@ static int OpenDecoder(vlc_object_t *p_this)
p_sys->pf_configure_vout = ConfigureVoutH264;
p_sys->pf_copy_extradata = CopyDecoderExtradataH264;
p_sys->pf_fill_reorder_info = FillReorderInfoH264;
p_sys->b_strict_reorder = false;
p_sys->b_poc_based_reorder = true;
p_sys->b_vt_need_keyframe = true;
p_sys->start_sync_state = STATE_BITSTREAM_WAITING_RAP;
break;
case kCMVideoCodecType_HEVC:
......@@ -1435,8 +1493,9 @@ static int OpenDecoder(vlc_object_t *p_this)
p_sys->pf_configure_vout = ConfigureVoutHEVC;
p_sys->pf_copy_extradata = CopyDecoderExtradataHEVC;
p_sys->pf_fill_reorder_info = FillReorderInfoHEVC;
p_sys->b_strict_reorder = true;
p_sys->b_poc_based_reorder = true;
p_sys->b_vt_need_keyframe = true;
p_sys->start_sync_state = STATE_BITSTREAM_WAITING_RAP;
break;
case kCMVideoCodecType_MPEG4Video:
......@@ -1448,6 +1507,8 @@ static int OpenDecoder(vlc_object_t *p_this)
break;
}
p_sys->sync_state = p_sys->start_sync_state;
if (p_sys->pf_codec_init && !p_sys->pf_codec_init(p_dec))
{
CloseDecoder(p_this);
......@@ -1461,7 +1522,7 @@ static int OpenDecoder(vlc_object_t *p_this)
i_ret = StartVideoToolbox(p_dec);
if (i_ret == VLC_SUCCESS) {
PtsInit(p_dec);
date_Set(&p_sys->pts, VLC_TICK_INVALID);
msg_Info(p_dec, "Using Video Toolbox to decode '%4.4s'",
(char *)&p_dec->fmt_in->i_codec);
} else {
......@@ -1769,10 +1830,8 @@ static int HandleVTStatus(decoder_t *p_dec, OSStatus status,
static void RequestFlush(decoder_t *p_dec)
{
decoder_sys_t *p_sys = p_dec->p_sys;
vlc_mutex_lock(&p_sys->lock);
p_sys->b_vt_flush = true;
vlc_mutex_unlock(&p_sys->lock);
Drain(p_dec, true);
date_Set(&p_sys->pts, VLC_TICK_INVALID);
}
static void Drain(decoder_t *p_dec, bool flush)
......@@ -1781,18 +1840,18 @@ static void Drain(decoder_t *p_dec, bool flush)
/* draining: return last pictures of the reordered queue */
vlc_mutex_lock(&p_sys->lock);
p_sys->b_vt_flush = true;
DrainDPBLocked(p_dec, flush);
p_sys->b_discard_decoder_output = flush;
vlc_mutex_unlock(&p_sys->lock);
if (p_sys->session && p_sys->b_vt_feed)
if (p_sys->session && p_sys->decoder_state == STATE_DECODER_STARTED)
VTDecompressionSessionWaitForAsynchronousFrames(p_sys->session);
vlc_mutex_lock(&p_sys->lock);
assert(RemoveOneFrameFromDPB(p_sys) == NULL);
p_sys->b_vt_flush = false;
p_sys->b_vt_feed = false;
p_sys->b_drop_blocks = false;
DrainDPBLocked(p_dec, flush);
picture_t *p_output;
assert(RemoveOneFrameFromDPB(p_sys, &p_output) == VLC_EGENERIC);
p_sys->b_discard_decoder_output = false;
p_sys->sync_state = p_sys->start_sync_state;
vlc_mutex_unlock(&p_sys->lock);
}
......@@ -1800,11 +1859,7 @@ static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
{
decoder_sys_t *p_sys = p_dec->p_sys;
if (p_sys->b_vt_flush)
{
Drain(p_dec, true);
PtsInit(p_dec);
}
pic_pacer_WaitAllocatableSlot(p_sys->pic_pacer);
if (p_block == NULL)
{
......@@ -1902,10 +1957,10 @@ static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
if (unlikely(p_block->i_flags&(BLOCK_FLAG_CORRUPTED)))
{
if (p_sys->b_vt_feed)
if (p_sys->sync_state == STATE_BITSTREAM_SYNCED)
{
Drain(p_dec, false);
PtsInit(p_dec);
date_Set(&p_sys->pts, VLC_TICK_INVALID);
}
goto skip;
}
......@@ -1954,10 +2009,25 @@ static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
}
}
if (!p_sys->b_vt_feed && p_sys->b_vt_need_keyframe && !p_info->b_keyframe)
if (p_sys->sync_state == STATE_BITSTREAM_WAITING_RAP)
{
free(p_info);
goto skip;
if(!p_info->b_keyframe)
{
msg_Dbg(p_dec, "discarding non recovery frame %"PRId64, p_info->pts);
free(p_info);
goto skip;
}
p_sys->sync_state = STATE_BITSTREAM_DISCARD_LEADING;
}
else if(p_sys->sync_state == STATE_BITSTREAM_DISCARD_LEADING)
{
if(p_info->b_leading)
{
msg_Dbg(p_dec, "discarding skipped leading frame %"PRId64, p_info->pts);
free(p_info);
goto skip;
}
p_sys->sync_state = STATE_BITSTREAM_SYNCED;
}
CMSampleBufferRef sampleBuffer =
......@@ -1978,12 +2048,20 @@ static int DecodeBlock(decoder_t *p_dec, block_t *p_block)
enum vtsession_status vtsession_status;
if (HandleVTStatus(p_dec, status, &vtsession_status) == VLC_SUCCESS)
{
p_sys->b_vt_feed = true;
pic_pacer_AccountScheduledDecode(p_sys->pic_pacer);
if(p_sys->decoder_state != STATE_DECODER_STARTED)
{
msg_Dbg(p_dec, "session accepted first frame %"PRId64, p_info->pts);
p_sys->decoder_state = STATE_DECODER_STARTED;
}
if (p_block->i_flags & BLOCK_FLAG_END_OF_SEQUENCE)
Drain( p_dec, false );
}
else
{
msg_Dbg(p_dec, "session rejected frame %"PRId64" with status %d", p_info->pts, status);
p_sys->sync_state = p_sys->start_sync_state;
vlc_mutex_lock(&p_sys->lock);
p_sys->vtsession_status = vtsession_status;
/* In case of abort, the decoder module will be reloaded next time
......@@ -2080,46 +2158,45 @@ video_context_OnPicReleased(vlc_video_context *vctx, unsigned nb_fields)
{
struct pic_pacer *pic_pacer =
vlc_video_context_GetCVPXPrivate(vctx, CVPX_VIDEO_CONTEXT_VIDEOTOOLBOX);
VLC_UNUSED(nb_fields);
vlc_mutex_lock(&pic_pacer->lock);
assert((int) pic_pacer->nb_field_out - nb_fields >= 0);
pic_pacer->nb_field_out -= nb_fields;
vlc_cond_signal(&pic_pacer->wait);
vlc_mutex_unlock(&pic_pacer->lock);
}
assert(pic_pacer->nb_out > 0);
pic_pacer->nb_out -= 1;
static void
pic_pacer_UpdateReorderMax(struct pic_pacer *pic_pacer, uint8_t pic_reorder_max,
uint8_t nb_field)
{
vlc_mutex_lock(&pic_pacer->lock);
/* our shrink condition */
if(pic_pacer->allocated_next < pic_pacer->allocated_max &&
pic_pacer->nb_out <= pic_pacer->allocated_next)
pic_pacer->allocated_max = pic_pacer->allocated_next;
pic_pacer->field_reorder_max = pic_reorder_max * (nb_field < 2 ? 2 : nb_field);
vlc_cond_signal(&pic_pacer->wait);
vlc_mutex_unlock(&pic_pacer->lock);
}
static int pic_pacer_Wait(struct pic_pacer *pic_pacer, const picture_t *pic)
static void
pic_pacer_UpdateReorderMax(struct pic_pacer *pic_pacer, uint8_t pic_reorder_max)
{
const uint8_t reserved_fields = 2 * (pic->i_nb_fields < 2 ? 2 : pic->i_nb_fields);
vlc_mutex_lock(&pic_pacer->lock);
/* Wait 200 ms max. We can't really know what the video output will do with
* output pictures (will they be rendered immediately ?), so don't wait
* infinitely. The output will be paced anyway by the vlc_cond_timedwait()
* call. */
vlc_tick_t deadline = vlc_tick_now() + VLC_TICK_FROM_MS(200);
int ret = 0;
while (ret == 0 && pic_pacer->field_reorder_max != 0
&& pic_pacer->nb_field_out >= pic_pacer->field_reorder_max + reserved_fields)
ret = vlc_cond_timedwait(&pic_pacer->wait, &pic_pacer->lock, deadline);
pic_pacer->nb_field_out += pic->i_nb_fields;
pic_reorder_max += PIC_PACER_ALLOCATABLE_MAX;
bool b_growing = pic_reorder_max > pic_pacer->allocated_max;
#ifdef PIC_PACER_DEBUG
fprintf(stderr, "updating pacer max %d/%d to %d\n",
pic_pacer->nb_out, pic_pacer->allocated_max, pic_reorder_max);
#endif
if(b_growing)
{
pic_pacer->allocated_max = pic_reorder_max;
pic_pacer->allocated_next = pic_reorder_max;
vlc_cond_signal(&pic_pacer->wait);
}
else
{
pic_pacer->allocated_next = pic_reorder_max;
}
vlc_mutex_unlock(&pic_pacer->lock);
return ret;
}
static void DecoderCallback(void *decompressionOutputRefCon,
......@@ -2136,7 +2213,7 @@ static void DecoderCallback(void *decompressionOutputRefCon,
frame_info_t *p_info = (frame_info_t *) sourceFrameRefCon;
vlc_mutex_lock(&p_sys->lock);
if (p_sys->b_vt_flush)
if (p_sys->b_discard_decoder_output)
goto end;
enum vtsession_status vtsession_status;
......@@ -2177,19 +2254,17 @@ static void DecoderCallback(void *decompressionOutputRefCon,
if (CVPixelBufferGetDataSize(imageBuffer) == 0)
goto end;
if (likely(p_info))
{
/* Unlock the mutex because decoder_NewPicture() is blocking. Indeed,
* it can wait indefinitely when the input is paused. */
vlc_mutex_unlock(&p_sys->lock);
if (unlikely(p_info == NULL))
goto end;
picture_t *p_pic = decoder_NewPicture(p_dec);
if (!p_pic)
goto unlocked_end;
/* Unlock the mutex because decoder_NewPicture() is blocking. Indeed,
* it can wait indefinitely when the input is paused. */
p_info->p_picture = p_pic;
vlc_mutex_unlock(&p_sys->lock);
picture_t *p_pic = decoder_NewPicture(p_dec);
if (p_pic)
{
p_pic->date = pts.value;
p_pic->b_force = p_info->b_eos;
p_pic->b_still = p_info->b_eos;
......@@ -2201,36 +2276,31 @@ static void DecoderCallback(void *decompressionOutputRefCon,
}
if (cvpxpic_attach(p_pic, imageBuffer, p_sys->vctx,
video_context_OnPicReleased) != VLC_SUCCESS)
video_context_OnPicReleased) == VLC_SUCCESS)
{
picture_Release(p_pic);
goto unlocked_end;
/* VT is not pacing frame allocation. If we are not fast enough to
* render (release) the output pictures, the VT session can end up
* allocating way too many frames. This can be problematic for 4K
* 10bits. To fix this issue, we ensure that we don't have too many
* output frames allocated by waiting for the vout to release them. */
pic_pacer_AccountAllocation(p_sys->pic_pacer);
}
}
/* VT is not pacing frame allocation. If we are not fast enough to
* render (release) the output pictures, the VT session can end up
* allocating way too many frames. This can be problematic for 4K
* 10bits. To fix this issue, we ensure that we don't have too many
* output frames allocated by waiting for the vout to release them. */
if (pic_pacer_Wait(p_sys->pic_pacer, p_pic))
msg_Warn(p_dec, "pic_pacer_Wait timed out");
vlc_mutex_lock(&p_sys->lock);
vlc_mutex_lock(&p_sys->lock);
if (p_sys->b_vt_flush)
{
picture_Release(p_pic);
goto end;
}
if (p_sys->b_discard_decoder_output)
picture_Release(p_pic);
else
p_info->p_picture = p_pic;
OnDecodedFrame( p_dec, p_info );
p_info = NULL;
}
OnDecodedFrame( p_dec, p_info );
p_info = NULL;
end:
vlc_mutex_unlock(&p_sys->lock);
unlocked_end:
free(p_info);
vlc_mutex_unlock(&p_sys->lock);
pic_pacer_AccountFinishedDecode(p_sys->pic_pacer);
return;
}
......