3 *****************************************************************************
4 * Copyright © 2014-2015 VideoLAN and VLC Authors
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
25 #include "FakeESOut.hpp"
26 #include "FakeESOutID.hpp"
27 #include "CommandsQueue.hpp"
28 #include <vlc_es_out.h>
29 #include <vlc_block.h>
32 using namespace adaptive
;
34 FakeESOut::FakeESOut( es_out_t
*es
, CommandsQueue
*queue
)
37 , commandsqueue( queue
)
38 , fakeesout( new es_out_t
)
39 , timestamps_offset( 0 )
40 , timestamps_expected( 0 )
41 , timestamps_check_done( false )
43 fakeesout
->pf_add
= esOutAdd_Callback
;
44 fakeesout
->pf_control
= esOutControl_Callback
;
45 fakeesout
->pf_del
= esOutDel_Callback
;
46 fakeesout
->pf_destroy
= esOutDestroy_Callback
;
47 fakeesout
->pf_send
= esOutSend_Callback
;
48 fakeesout
->p_sys
= (es_out_sys_t
*) this;
50 vlc_mutex_init(&lock
);
53 es_out_t
* FakeESOut::getEsOut()
58 FakeESOut::~FakeESOut()
64 vlc_mutex_destroy(&lock
);
67 void FakeESOut::setExpectedTimestampOffset(mtime_t offset
)
69 vlc_mutex_lock(&lock
);
70 timestamps_offset
= 0;
71 timestamps_expected
= offset
;
72 timestamps_check_done
= false;
73 vlc_mutex_unlock(&lock
);
76 void FakeESOut::setTimestampOffset(mtime_t offset
)
78 vlc_mutex_lock(&lock
);
79 timestamps_offset
= offset
;
80 timestamps_check_done
= true;
81 vlc_mutex_unlock(&lock
);
84 void FakeESOut::setExtraInfoProvider( ExtraFMTInfoInterface
*extra
)
86 vlc_mutex_lock(&lock
);
88 vlc_mutex_unlock(&lock
);
91 FakeESOutID
* FakeESOut::createNewID( const es_format_t
*p_fmt
)
94 es_format_Init( &fmtcopy
, p_fmt
->i_cat
, p_fmt
->i_codec
);
95 es_format_Copy( &fmtcopy
, p_fmt
);
96 fmtcopy
.i_group
= 0; /* Always ignore group for adaptive */
99 vlc_mutex_lock(&lock
);
102 extrainfo
->fillExtraFMTInfo( &fmtcopy
);
104 FakeESOutID
*es_id
= new (std::nothrow
) FakeESOutID( this, &fmtcopy
);
106 fakeesidlist
.push_back( es_id
);
108 vlc_mutex_unlock(&lock
);
110 es_format_Clean( &fmtcopy
);
115 void FakeESOut::createOrRecycleRealEsID( FakeESOutID
*es_id
)
117 std::list
<FakeESOutID
*>::iterator it
;
118 es_out_id_t
*realid
= NULL
;
120 vlc_mutex_lock(&lock
);
122 bool b_select
= false;
123 for( it
=recycle_candidates
.begin(); it
!=recycle_candidates
.end(); ++it
)
125 FakeESOutID
*cand
= *it
;
126 if ( cand
->isCompatible( es_id
) )
128 realid
= cand
->realESID();
129 cand
->setRealESID( NULL
);
131 recycle_candidates
.erase( it
);
134 else if( cand
->getFmt()->i_cat
== es_id
->getFmt()->i_cat
&& cand
->realESID() )
136 /* We need to enforce same selection when not reused
137 Otherwise the es will select any other compatible track
138 and will end this in a activate/select loop when reactivating a track */
139 es_out_Control( real_es_out
, ES_OUT_GET_ES_STATE
, cand
->realESID(), &b_select
);
146 realid
= es_out_Add( real_es_out
, es_id
->getFmt() );
148 es_out_Control( real_es_out
, ES_OUT_SET_ES_STATE
, realid
, b_select
);
151 es_id
->setRealESID( realid
);
153 vlc_mutex_unlock(&lock
);
156 mtime_t
FakeESOut::getTimestampOffset() const
158 vlc_mutex_lock(const_cast<vlc_mutex_t
*>(&lock
));
159 mtime_t time
= timestamps_offset
;
160 vlc_mutex_unlock(const_cast<vlc_mutex_t
*>(&lock
));
164 size_t FakeESOut::esCount() const
167 std::list
<FakeESOutID
*>::const_iterator it
;
168 vlc_mutex_lock(const_cast<vlc_mutex_t
*>(&lock
));
169 for( it
=fakeesidlist
.begin(); it
!=fakeesidlist
.end(); ++it
)
170 if( (*it
)->realESID() )
172 vlc_mutex_unlock(const_cast<vlc_mutex_t
*>(&lock
));
176 void FakeESOut::schedulePCRReset()
178 AbstractCommand
*command
= commandsqueue
->factory()->creatEsOutControlResetPCRCommand();
179 if( likely(command
) )
180 commandsqueue
->Schedule( command
);
183 void FakeESOut::scheduleAllForDeletion()
185 std::list
<FakeESOutID
*>::const_iterator it
;
186 vlc_mutex_lock(&lock
);
187 for( it
=fakeesidlist
.begin(); it
!=fakeesidlist
.end(); ++it
)
189 FakeESOutID
*es_id
= *it
;
190 if(!es_id
->scheduledForDeletion())
192 AbstractCommand
*command
= commandsqueue
->factory()->createEsOutDelCommand( es_id
);
193 if( likely(command
) )
195 commandsqueue
->Schedule( command
);
196 es_id
->setScheduledForDeletion();
200 vlc_mutex_unlock(&lock
);
203 void FakeESOut::recycleAll()
205 /* Only used when demux is killed and commands queue is cancelled */
206 commandsqueue
->Abort( true );
207 assert(commandsqueue
->isEmpty());
208 vlc_mutex_lock(&lock
);
209 recycle_candidates
.splice( recycle_candidates
.end(), fakeesidlist
);
210 vlc_mutex_unlock(&lock
);
215 vlc_mutex_lock(&lock
);
216 if( recycle_candidates
.empty() )
218 vlc_mutex_unlock(&lock
);
222 std::list
<FakeESOutID
*>::iterator it
;
223 for( it
=recycle_candidates
.begin(); it
!=recycle_candidates
.end(); ++it
)
225 if( (*it
)->realESID() )
227 es_out_Control( real_es_out
, ES_OUT_SET_ES_STATE
, (*it
)->realESID(), false );
228 es_out_Del( real_es_out
, (*it
)->realESID() );
232 recycle_candidates
.clear();
233 vlc_mutex_unlock(&lock
);
236 bool FakeESOut::hasSelectedEs() const
238 bool b_selected
= false;
239 std::list
<FakeESOutID
*>::const_iterator it
;
240 vlc_mutex_lock(const_cast<vlc_mutex_t
*>(&lock
));
241 for( it
=fakeesidlist
.begin(); it
!=fakeesidlist
.end() && !b_selected
; ++it
)
243 FakeESOutID
*esID
= *it
;
244 if( esID
->realESID() )
245 es_out_Control( real_es_out
, ES_OUT_GET_ES_STATE
, esID
->realESID(), &b_selected
);
247 vlc_mutex_unlock(const_cast<vlc_mutex_t
*>(&lock
));
251 bool FakeESOut::decodersDrained()
253 bool b_drained
= true;
254 std::list
<FakeESOutID
*>::const_iterator it
;
255 vlc_mutex_lock(&lock
);
256 for( it
=fakeesidlist
.begin(); it
!=fakeesidlist
.end(); ++it
)
258 FakeESOutID
*esID
= *it
;
259 if( esID
->realESID() && esID
->getFmt()->i_cat
!= AUDIO_ES
) /* Broken GET_EMPTY */
262 es_out_Control( real_es_out
, ES_OUT_GET_EMPTY
, &b_empty
);
263 b_drained
&= b_empty
;
266 vlc_mutex_unlock(&lock
);
270 bool FakeESOut::restarting() const
272 vlc_mutex_lock(const_cast<vlc_mutex_t
*>(&lock
));
273 bool b
= !recycle_candidates
.empty();
274 vlc_mutex_unlock(const_cast<vlc_mutex_t
*>(&lock
));
278 void FakeESOut::recycle( FakeESOutID
*id
)
280 vlc_mutex_lock(&lock
);
281 fakeesidlist
.remove( id
);
282 recycle_candidates
.push_back( id
);
283 vlc_mutex_unlock(&lock
);
286 /* Static callbacks */
287 /* Always pass Fake ES ID to slave demuxes, it is just an opaque struct to them */
288 es_out_id_t
* FakeESOut::esOutAdd_Callback(es_out_t
*fakees
, const es_format_t
*p_fmt
)
290 FakeESOut
*me
= (FakeESOut
*) fakees
->p_sys
;
292 if( p_fmt
->i_cat
!= VIDEO_ES
&& p_fmt
->i_cat
!= AUDIO_ES
&& p_fmt
->i_cat
!= SPU_ES
)
295 /* Feed the slave demux/stream_Demux with FakeESOutID struct,
296 * we'll create real ES later on main demux on execution */
297 FakeESOutID
*es_id
= me
->createNewID( p_fmt
);
300 assert(!es_id
->scheduledForDeletion());
301 AbstractCommand
*command
= me
->commandsqueue
->factory()->createEsOutAddCommand( es_id
);
302 if( likely(command
) )
304 me
->commandsqueue
->Schedule( command
);
305 return reinterpret_cast<es_out_id_t
*>(es_id
);
315 void FakeESOut::checkTimestampsStart(mtime_t i_start
)
317 if( i_start
== VLC_TS_INVALID
)
320 vlc_mutex_lock(&lock
);
321 if( !timestamps_check_done
)
323 if( i_start
< CLOCK_FREQ
) /* Starts 0 */
324 timestamps_offset
= timestamps_expected
;
325 timestamps_check_done
= true;
327 vlc_mutex_unlock(&lock
);
330 int FakeESOut::esOutSend_Callback(es_out_t
*fakees
, es_out_id_t
*p_es
, block_t
*p_block
)
332 FakeESOut
*me
= (FakeESOut
*) fakees
->p_sys
;
333 FakeESOutID
*es_id
= reinterpret_cast<FakeESOutID
*>( p_es
);
334 assert(!es_id
->scheduledForDeletion());
336 me
->checkTimestampsStart( p_block
->i_dts
);
338 mtime_t offset
= me
->getTimestampOffset();
339 if( p_block
->i_dts
> VLC_TS_INVALID
)
341 p_block
->i_dts
+= offset
;
342 if( p_block
->i_pts
> VLC_TS_INVALID
)
343 p_block
->i_pts
+= offset
;
345 AbstractCommand
*command
= me
->commandsqueue
->factory()->createEsOutSendCommand( es_id
, p_block
);
346 if( likely(command
) )
348 me
->commandsqueue
->Schedule( command
);
354 void FakeESOut::esOutDel_Callback(es_out_t
*fakees
, es_out_id_t
*p_es
)
356 FakeESOut
*me
= (FakeESOut
*) fakees
->p_sys
;
357 FakeESOutID
*es_id
= reinterpret_cast<FakeESOutID
*>( p_es
);
358 AbstractCommand
*command
= me
->commandsqueue
->factory()->createEsOutDelCommand( es_id
);
359 if( likely(command
) )
361 es_id
->setScheduledForDeletion();
362 me
->commandsqueue
->Schedule( command
);
366 int FakeESOut::esOutControl_Callback(es_out_t
*fakees
, int i_query
, va_list args
)
368 FakeESOut
*me
= (FakeESOut
*) fakees
->p_sys
;
373 case ES_OUT_SET_GROUP_PCR
:
376 if( i_query
== ES_OUT_SET_GROUP_PCR
)
377 i_group
= va_arg( args
, int );
380 int64_t pcr
= va_arg( args
, int64_t );
381 me
->checkTimestampsStart( pcr
);
382 pcr
+= me
->getTimestampOffset();
383 AbstractCommand
*command
= me
->commandsqueue
->factory()->createEsOutControlPCRCommand( i_group
, pcr
);
384 if( likely(command
) )
386 me
->commandsqueue
->Schedule( command
);
392 case ES_OUT_SET_GROUP_META
:
394 static_cast<void>(va_arg( args
, int )); /* ignore group */
395 const vlc_meta_t
*p_meta
= va_arg( args
, const vlc_meta_t
* );
396 AbstractCommand
*command
= me
->commandsqueue
->factory()->createEsOutMetaCommand( -1, p_meta
);
397 if( likely(command
) )
399 me
->commandsqueue
->Schedule( command
);
405 /* For others, we don't have the delorean, so always lie */
406 case ES_OUT_GET_ES_STATE
:
408 static_cast<void>(va_arg( args
, es_out_id_t
* ));
409 bool *pb
= va_arg( args
, bool * );
415 case ES_OUT_SET_ES_DEFAULT
:
416 case ES_OUT_SET_ES_STATE
:
423 void FakeESOut::esOutDestroy_Callback(es_out_t
*fakees
)
425 FakeESOut
*me
= (FakeESOut
*) fakees
->p_sys
;
426 AbstractCommand
*command
= me
->commandsqueue
->factory()->createEsOutDestroyCommand();
427 if( likely(command
) )
428 me
->commandsqueue
->Schedule( command
);
430 /* !Static callbacks */