2000-02-13 05:31:35 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* input.c: input thread
|
2000-03-03 08:03:34 +01:00
|
|
|
*****************************************************************************
|
LGPL
Re-license almost all of libVLC and libVLCcore to LGPLv2.1+
This move was authorized by the developers, either:
- by e-mail,
- by vote at the VideoLAN Dev Days 2011,
- on the license website,
- in a contract, oral or written.
No objection was raised, so far.
The developers agreeing are:
Justus Piater
Alexis Ballier
Alexander Bethke
Mohammed Adnène Trojette
Alex Converse
Alexey Sokolov
Alexis de Lattre
Andre Pang
Anthony Loiseau
Cyril Deguet
André Weber
Boris Dorès
Brieuc Jeunhomme
Benjamin Drung
Hugo Beauzée-Luyssen
Benoit Steiner
Benjamin Pracht
Bernie Purcell
Przemyslaw Fiala
Arnaud de Bossoreille de Ribou
Brad Smith
Nick Briggs
Christopher Rath
Christophe Courtaut
Christopher Mueller
Clement Chesnin
Andres Krapf
Damien Fouilleul
David Flynn
Sebastien Zwickert
Antoine Cellerier
Jérôme Decoodt
Jérome Decoodt
Dylan Yudaken
Eduard Babayan
Eugenio Jarosiewicz
Elliot Murphy
Eric Petit
Erwan Tulou
Etienne Membrives
Ludovic Fauvet
Fabio Ritrovato
Tobias Güntner
Jakub Wieczorek
Frédéric Crozat
Francois Cartegnie
Laurent Aimar
Florian G. Pflug
Felix Paul Kühne
Frank Enderle
Rafaël Carré
Simon Latapie
Gildas Bazin
Geoffroy Couprie
Julien / Gellule
Gildas Bazin
Arnaud Schauly
Toralf Niebuhr
Vicente Jimenez Aguilar
Derk-Jan Hartman
Henri Fallon
Ilkka Ollakka
Olivier Teulière
Rémi Duraffort
Jakob Leben
Jean-Baptiste Kempf
Jean-Paul Saman
Jean-Philippe Grimaldi
Jean-François Massol
Gaël Hendryckx
Jakob Leben
Jean-Marc Dressler
Jai Menon
Johan Bilien
Johann Ransay
Joris van Rooij
JP Dinger
Jean-Philippe André
Adrien Grand
Juha Jeronen
Juho Vähä-Herttua
Kaarlo Raiha
Kaarlo Raiha
Kamil Baldyga
Keary Griffin
Ken Self
KO Myung-Hun
Pierre Ynard
Filippo Carone
Loïc Minier
Luca Barbato
Lucas C. Villa Real
Lukas Durfina
Adrien Maglo
Marc Ariberti
Mark Lee
Mark Moriarty
Martin Storsjö
Christophe Massiot
Michel Kaempf
Marian Ďurkovič
Mirsal Ennaime
Carlo Calabrò
Damien Lucas
Naohiro Koriyama
Basos G
Pierre Baillet
Vincent Penquerc'h
Olivier Aubert
Pankaj Yadav
Paul Corke
Pierre d'Herbemont
Philippe Morin
Antoine Lejeune
Michael Ploujnikov
Jean-Marc Dressler
Michael Hanselmann
Rafaël Carré
Ramiro Polla
Rémi Denis-Courmont
Renaud Dartus
Richard Shepherd
Faustino Osuna
Arnaud Vallat
Rob Jonson
Robert Jedrzejczyk
Steve Lhomme
Rocky Bernstein
Romain Goyet
Rov Juvano
Sam Hocevar
Martin T. H. Sandsmark
Sebastian Birk
Sébastien Escudier
Vincent Seguin
Fabio Ritrovato
Sigmund Augdal Helberg
Casian Andrei
Srikanth Raju
Hannes Domani
Stéphane Borel
Stephan Krempel
Stephan Assmus
Tony Castley
Pavlov Konstantin
Eric Petit
Tanguy Krotoff
Dennis van Amerongen
Michel Lespinasse
Can Wu
Xavier Marchesini
Sébastien Toque
Christophe Mutricy
Yoann Peronneau
Yohann Martineau
Yuval Tze
Scott Caudle
Clément Stenac
It is possible, that some minor piece of code was badly tracked, for
some reasons (SVN, mainly) or that some small developers did not answer.
However, as an "œuvre collective", defined as in "CPI 113-2 alinéa 3",
and seeing "Cour. Cass. 17 Mai 1978", and seeing that the editor and
the very vast majority of developers have agreed (> 99.99% of the code,
> 99% of developers), we are fine here.
2011-11-27 21:44:15 +01:00
|
|
|
* Copyright (C) 1998-2007 VLC authors and VideoLAN
|
2000-03-03 08:03:34 +01:00
|
|
|
*
|
2001-02-08 14:52:35 +01:00
|
|
|
* Authors: Christophe Massiot <massiot@via.ecp.fr>
|
2004-06-22 21:29:57 +02:00
|
|
|
* Laurent Aimar <fenrir@via.ecp.fr>
|
2000-03-03 08:03:34 +01:00
|
|
|
*
|
LGPL
Re-license almost all of libVLC and libVLCcore to LGPLv2.1+
This move was authorized by the developers, either:
- by e-mail,
- by vote at the VideoLAN Dev Days 2011,
- on the license website,
- in a contract, oral or written.
No objection was raised, so far.
The developers agreeing are:
Justus Piater
Alexis Ballier
Alexander Bethke
Mohammed Adnène Trojette
Alex Converse
Alexey Sokolov
Alexis de Lattre
Andre Pang
Anthony Loiseau
Cyril Deguet
André Weber
Boris Dorès
Brieuc Jeunhomme
Benjamin Drung
Hugo Beauzée-Luyssen
Benoit Steiner
Benjamin Pracht
Bernie Purcell
Przemyslaw Fiala
Arnaud de Bossoreille de Ribou
Brad Smith
Nick Briggs
Christopher Rath
Christophe Courtaut
Christopher Mueller
Clement Chesnin
Andres Krapf
Damien Fouilleul
David Flynn
Sebastien Zwickert
Antoine Cellerier
Jérôme Decoodt
Jérome Decoodt
Dylan Yudaken
Eduard Babayan
Eugenio Jarosiewicz
Elliot Murphy
Eric Petit
Erwan Tulou
Etienne Membrives
Ludovic Fauvet
Fabio Ritrovato
Tobias Güntner
Jakub Wieczorek
Frédéric Crozat
Francois Cartegnie
Laurent Aimar
Florian G. Pflug
Felix Paul Kühne
Frank Enderle
Rafaël Carré
Simon Latapie
Gildas Bazin
Geoffroy Couprie
Julien / Gellule
Gildas Bazin
Arnaud Schauly
Toralf Niebuhr
Vicente Jimenez Aguilar
Derk-Jan Hartman
Henri Fallon
Ilkka Ollakka
Olivier Teulière
Rémi Duraffort
Jakob Leben
Jean-Baptiste Kempf
Jean-Paul Saman
Jean-Philippe Grimaldi
Jean-François Massol
Gaël Hendryckx
Jakob Leben
Jean-Marc Dressler
Jai Menon
Johan Bilien
Johann Ransay
Joris van Rooij
JP Dinger
Jean-Philippe André
Adrien Grand
Juha Jeronen
Juho Vähä-Herttua
Kaarlo Raiha
Kaarlo Raiha
Kamil Baldyga
Keary Griffin
Ken Self
KO Myung-Hun
Pierre Ynard
Filippo Carone
Loïc Minier
Luca Barbato
Lucas C. Villa Real
Lukas Durfina
Adrien Maglo
Marc Ariberti
Mark Lee
Mark Moriarty
Martin Storsjö
Christophe Massiot
Michel Kaempf
Marian Ďurkovič
Mirsal Ennaime
Carlo Calabrò
Damien Lucas
Naohiro Koriyama
Basos G
Pierre Baillet
Vincent Penquerc'h
Olivier Aubert
Pankaj Yadav
Paul Corke
Pierre d'Herbemont
Philippe Morin
Antoine Lejeune
Michael Ploujnikov
Jean-Marc Dressler
Michael Hanselmann
Rafaël Carré
Ramiro Polla
Rémi Denis-Courmont
Renaud Dartus
Richard Shepherd
Faustino Osuna
Arnaud Vallat
Rob Jonson
Robert Jedrzejczyk
Steve Lhomme
Rocky Bernstein
Romain Goyet
Rov Juvano
Sam Hocevar
Martin T. H. Sandsmark
Sebastian Birk
Sébastien Escudier
Vincent Seguin
Fabio Ritrovato
Sigmund Augdal Helberg
Casian Andrei
Srikanth Raju
Hannes Domani
Stéphane Borel
Stephan Krempel
Stephan Assmus
Tony Castley
Pavlov Konstantin
Eric Petit
Tanguy Krotoff
Dennis van Amerongen
Michel Lespinasse
Can Wu
Xavier Marchesini
Sébastien Toque
Christophe Mutricy
Yoann Peronneau
Yohann Martineau
Yuval Tze
Scott Caudle
Clément Stenac
It is possible, that some minor piece of code was badly tracked, for
some reasons (SVN, mainly) or that some small developers did not answer.
However, as an "œuvre collective", defined as in "CPI 113-2 alinéa 3",
and seeing "Cour. Cass. 17 Mai 1978", and seeing that the editor and
the very vast majority of developers have agreed (> 99.99% of the code,
> 99% of developers), we are fine here.
2011-11-27 21:44:15 +01:00
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU Lesser General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2.1 of the License, or
|
2000-03-03 08:03:34 +01:00
|
|
|
* (at your option) any later version.
|
2002-12-06 17:34:08 +01:00
|
|
|
*
|
2000-03-03 08:03:34 +01:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
LGPL
Re-license almost all of libVLC and libVLCcore to LGPLv2.1+
This move was authorized by the developers, either:
- by e-mail,
- by vote at the VideoLAN Dev Days 2011,
- on the license website,
- in a contract, oral or written.
No objection was raised, so far.
The developers agreeing are:
Justus Piater
Alexis Ballier
Alexander Bethke
Mohammed Adnène Trojette
Alex Converse
Alexey Sokolov
Alexis de Lattre
Andre Pang
Anthony Loiseau
Cyril Deguet
André Weber
Boris Dorès
Brieuc Jeunhomme
Benjamin Drung
Hugo Beauzée-Luyssen
Benoit Steiner
Benjamin Pracht
Bernie Purcell
Przemyslaw Fiala
Arnaud de Bossoreille de Ribou
Brad Smith
Nick Briggs
Christopher Rath
Christophe Courtaut
Christopher Mueller
Clement Chesnin
Andres Krapf
Damien Fouilleul
David Flynn
Sebastien Zwickert
Antoine Cellerier
Jérôme Decoodt
Jérome Decoodt
Dylan Yudaken
Eduard Babayan
Eugenio Jarosiewicz
Elliot Murphy
Eric Petit
Erwan Tulou
Etienne Membrives
Ludovic Fauvet
Fabio Ritrovato
Tobias Güntner
Jakub Wieczorek
Frédéric Crozat
Francois Cartegnie
Laurent Aimar
Florian G. Pflug
Felix Paul Kühne
Frank Enderle
Rafaël Carré
Simon Latapie
Gildas Bazin
Geoffroy Couprie
Julien / Gellule
Gildas Bazin
Arnaud Schauly
Toralf Niebuhr
Vicente Jimenez Aguilar
Derk-Jan Hartman
Henri Fallon
Ilkka Ollakka
Olivier Teulière
Rémi Duraffort
Jakob Leben
Jean-Baptiste Kempf
Jean-Paul Saman
Jean-Philippe Grimaldi
Jean-François Massol
Gaël Hendryckx
Jakob Leben
Jean-Marc Dressler
Jai Menon
Johan Bilien
Johann Ransay
Joris van Rooij
JP Dinger
Jean-Philippe André
Adrien Grand
Juha Jeronen
Juho Vähä-Herttua
Kaarlo Raiha
Kaarlo Raiha
Kamil Baldyga
Keary Griffin
Ken Self
KO Myung-Hun
Pierre Ynard
Filippo Carone
Loïc Minier
Luca Barbato
Lucas C. Villa Real
Lukas Durfina
Adrien Maglo
Marc Ariberti
Mark Lee
Mark Moriarty
Martin Storsjö
Christophe Massiot
Michel Kaempf
Marian Ďurkovič
Mirsal Ennaime
Carlo Calabrò
Damien Lucas
Naohiro Koriyama
Basos G
Pierre Baillet
Vincent Penquerc'h
Olivier Aubert
Pankaj Yadav
Paul Corke
Pierre d'Herbemont
Philippe Morin
Antoine Lejeune
Michael Ploujnikov
Jean-Marc Dressler
Michael Hanselmann
Rafaël Carré
Ramiro Polla
Rémi Denis-Courmont
Renaud Dartus
Richard Shepherd
Faustino Osuna
Arnaud Vallat
Rob Jonson
Robert Jedrzejczyk
Steve Lhomme
Rocky Bernstein
Romain Goyet
Rov Juvano
Sam Hocevar
Martin T. H. Sandsmark
Sebastian Birk
Sébastien Escudier
Vincent Seguin
Fabio Ritrovato
Sigmund Augdal Helberg
Casian Andrei
Srikanth Raju
Hannes Domani
Stéphane Borel
Stephan Krempel
Stephan Assmus
Tony Castley
Pavlov Konstantin
Eric Petit
Tanguy Krotoff
Dennis van Amerongen
Michel Lespinasse
Can Wu
Xavier Marchesini
Sébastien Toque
Christophe Mutricy
Yoann Peronneau
Yohann Martineau
Yuval Tze
Scott Caudle
Clément Stenac
It is possible, that some minor piece of code was badly tracked, for
some reasons (SVN, mainly) or that some small developers did not answer.
However, as an "œuvre collective", defined as in "CPI 113-2 alinéa 3",
and seeing "Cour. Cass. 17 Mai 1978", and seeing that the editor and
the very vast majority of developers have agreed (> 99.99% of the code,
> 99% of developers), we are fine here.
2011-11-27 21:44:15 +01:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Lesser General Public License for more details.
|
2000-03-03 08:03:34 +01:00
|
|
|
*
|
LGPL
Re-license almost all of libVLC and libVLCcore to LGPLv2.1+
This move was authorized by the developers, either:
- by e-mail,
- by vote at the VideoLAN Dev Days 2011,
- on the license website,
- in a contract, oral or written.
No objection was raised, so far.
The developers agreeing are:
Justus Piater
Alexis Ballier
Alexander Bethke
Mohammed Adnène Trojette
Alex Converse
Alexey Sokolov
Alexis de Lattre
Andre Pang
Anthony Loiseau
Cyril Deguet
André Weber
Boris Dorès
Brieuc Jeunhomme
Benjamin Drung
Hugo Beauzée-Luyssen
Benoit Steiner
Benjamin Pracht
Bernie Purcell
Przemyslaw Fiala
Arnaud de Bossoreille de Ribou
Brad Smith
Nick Briggs
Christopher Rath
Christophe Courtaut
Christopher Mueller
Clement Chesnin
Andres Krapf
Damien Fouilleul
David Flynn
Sebastien Zwickert
Antoine Cellerier
Jérôme Decoodt
Jérome Decoodt
Dylan Yudaken
Eduard Babayan
Eugenio Jarosiewicz
Elliot Murphy
Eric Petit
Erwan Tulou
Etienne Membrives
Ludovic Fauvet
Fabio Ritrovato
Tobias Güntner
Jakub Wieczorek
Frédéric Crozat
Francois Cartegnie
Laurent Aimar
Florian G. Pflug
Felix Paul Kühne
Frank Enderle
Rafaël Carré
Simon Latapie
Gildas Bazin
Geoffroy Couprie
Julien / Gellule
Gildas Bazin
Arnaud Schauly
Toralf Niebuhr
Vicente Jimenez Aguilar
Derk-Jan Hartman
Henri Fallon
Ilkka Ollakka
Olivier Teulière
Rémi Duraffort
Jakob Leben
Jean-Baptiste Kempf
Jean-Paul Saman
Jean-Philippe Grimaldi
Jean-François Massol
Gaël Hendryckx
Jakob Leben
Jean-Marc Dressler
Jai Menon
Johan Bilien
Johann Ransay
Joris van Rooij
JP Dinger
Jean-Philippe André
Adrien Grand
Juha Jeronen
Juho Vähä-Herttua
Kaarlo Raiha
Kaarlo Raiha
Kamil Baldyga
Keary Griffin
Ken Self
KO Myung-Hun
Pierre Ynard
Filippo Carone
Loïc Minier
Luca Barbato
Lucas C. Villa Real
Lukas Durfina
Adrien Maglo
Marc Ariberti
Mark Lee
Mark Moriarty
Martin Storsjö
Christophe Massiot
Michel Kaempf
Marian Ďurkovič
Mirsal Ennaime
Carlo Calabrò
Damien Lucas
Naohiro Koriyama
Basos G
Pierre Baillet
Vincent Penquerc'h
Olivier Aubert
Pankaj Yadav
Paul Corke
Pierre d'Herbemont
Philippe Morin
Antoine Lejeune
Michael Ploujnikov
Jean-Marc Dressler
Michael Hanselmann
Rafaël Carré
Ramiro Polla
Rémi Denis-Courmont
Renaud Dartus
Richard Shepherd
Faustino Osuna
Arnaud Vallat
Rob Jonson
Robert Jedrzejczyk
Steve Lhomme
Rocky Bernstein
Romain Goyet
Rov Juvano
Sam Hocevar
Martin T. H. Sandsmark
Sebastian Birk
Sébastien Escudier
Vincent Seguin
Fabio Ritrovato
Sigmund Augdal Helberg
Casian Andrei
Srikanth Raju
Hannes Domani
Stéphane Borel
Stephan Krempel
Stephan Assmus
Tony Castley
Pavlov Konstantin
Eric Petit
Tanguy Krotoff
Dennis van Amerongen
Michel Lespinasse
Can Wu
Xavier Marchesini
Sébastien Toque
Christophe Mutricy
Yoann Peronneau
Yohann Martineau
Yuval Tze
Scott Caudle
Clément Stenac
It is possible, that some minor piece of code was badly tracked, for
some reasons (SVN, mainly) or that some small developers did not answer.
However, as an "œuvre collective", defined as in "CPI 113-2 alinéa 3",
and seeing "Cour. Cass. 17 Mai 1978", and seeing that the editor and
the very vast majority of developers have agreed (> 99.99% of the code,
> 99% of developers), we are fine here.
2011-11-27 21:44:15 +01:00
|
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
2000-02-13 05:31:35 +01:00
|
|
|
*****************************************************************************/
|
1999-08-08 14:42:54 +02:00
|
|
|
|
2000-02-13 05:31:35 +01:00
|
|
|
/*****************************************************************************
|
1999-08-08 14:42:54 +02:00
|
|
|
* Preamble
|
2000-02-13 05:31:35 +01:00
|
|
|
*****************************************************************************/
|
2008-01-23 22:50:58 +01:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2008-05-31 20:56:22 +02:00
|
|
|
#include <vlc_common.h>
|
2019-05-31 12:32:30 +02:00
|
|
|
#include <vlc_decoder.h>
|
2001-05-31 05:12:49 +02:00
|
|
|
|
2007-10-21 21:17:11 +02:00
|
|
|
#include <limits.h>
|
2008-01-24 17:08:13 +01:00
|
|
|
#include <assert.h>
|
2012-01-27 22:06:50 +01:00
|
|
|
#include <sys/stat.h>
|
2007-08-20 20:59:30 +02:00
|
|
|
|
2004-06-22 21:29:57 +02:00
|
|
|
#include "input_internal.h"
|
2008-11-20 21:49:51 +01:00
|
|
|
#include "event.h"
|
2008-10-13 19:52:33 +02:00
|
|
|
#include "es_out.h"
|
2008-10-13 19:57:51 +02:00
|
|
|
#include "demux.h"
|
2008-12-02 19:16:17 +01:00
|
|
|
#include "item.h"
|
2009-03-01 09:40:11 +01:00
|
|
|
#include "resource.h"
|
2017-03-17 03:22:32 +01:00
|
|
|
#include "stream.h"
|
2020-10-10 11:57:49 +02:00
|
|
|
#include "stream_output/stream_output.h"
|
2000-12-18 16:31:47 +01:00
|
|
|
|
2017-07-07 15:05:24 +02:00
|
|
|
#include <vlc_aout.h>
|
2009-03-05 20:09:21 +01:00
|
|
|
#include <vlc_dialog.h>
|
2006-11-26 15:20:34 +01:00
|
|
|
#include <vlc_url.h>
|
|
|
|
#include <vlc_charset.h>
|
2010-02-07 14:18:02 +01:00
|
|
|
#include <vlc_fs.h>
|
2008-08-26 23:10:56 +02:00
|
|
|
#include <vlc_strings.h>
|
2010-07-27 21:11:58 +02:00
|
|
|
#include <vlc_modules.h>
|
2016-12-03 12:46:28 +01:00
|
|
|
#include <vlc_stream.h>
|
2016-12-03 12:38:09 +01:00
|
|
|
#include <vlc_stream_extractor.h>
|
2017-07-19 10:55:14 +02:00
|
|
|
#include <vlc_renderer_discovery.h>
|
2020-04-01 16:15:39 +02:00
|
|
|
#include <vlc_hash.h>
|
2006-06-16 21:05:55 +02:00
|
|
|
|
2000-02-13 05:31:35 +01:00
|
|
|
/*****************************************************************************
|
1999-08-08 14:42:54 +02:00
|
|
|
* Local prototypes
|
2000-02-13 05:31:35 +01:00
|
|
|
*****************************************************************************/
|
2015-10-28 17:43:36 +01:00
|
|
|
static void *Run( void * );
|
|
|
|
static void *Preparse( void * );
|
2004-06-22 21:29:57 +02:00
|
|
|
|
2019-05-31 15:26:56 +02:00
|
|
|
static void Destroy ( input_thread_t *p_input );
|
2006-09-24 15:13:40 +02:00
|
|
|
static int Init ( input_thread_t *p_input );
|
2005-11-09 14:44:49 +01:00
|
|
|
static void End ( input_thread_t *p_input );
|
2009-09-14 23:22:49 +02:00
|
|
|
static void MainLoop( input_thread_t *p_input, bool b_interactive );
|
2004-06-22 21:29:57 +02:00
|
|
|
|
2018-06-25 10:03:48 +02:00
|
|
|
static inline int ControlPop( input_thread_t *, int *, input_control_param_t *, vlc_tick_t i_deadline, bool b_postpone_seek );
|
2018-09-04 10:10:52 +02:00
|
|
|
static void ControlRelease( int i_type, const input_control_param_t *p_param );
|
2009-11-28 11:43:24 +01:00
|
|
|
static bool ControlIsSeekRequest( int i_type );
|
2018-06-25 10:03:48 +02:00
|
|
|
static bool Control( input_thread_t *, int, input_control_param_t );
|
2018-06-22 13:19:24 +02:00
|
|
|
static void ControlPause( input_thread_t *, vlc_tick_t );
|
2004-03-06 00:26:36 +01:00
|
|
|
|
2008-12-01 22:53:25 +01:00
|
|
|
static int UpdateTitleSeekpointFromDemux( input_thread_t * );
|
|
|
|
static void UpdateGenericFromDemux( input_thread_t * );
|
2012-12-05 23:07:18 +01:00
|
|
|
static void UpdateTitleListfromDemux( input_thread_t * );
|
1999-08-08 14:42:54 +02:00
|
|
|
|
2011-09-25 15:56:18 +02:00
|
|
|
static void MRLSections( const char *, int *, int *, int *, int *);
|
2004-06-25 00:21:36 +02:00
|
|
|
|
2020-02-26 13:09:26 +01:00
|
|
|
static input_source_t *InputSourceNew( const char *psz_mrl );
|
2020-02-26 14:43:13 +01:00
|
|
|
static int InputSourceInit( input_source_t *in, input_thread_t *p_input,
|
|
|
|
const char *psz_mrl,
|
|
|
|
const char *psz_forced_demux, bool b_in_can_fail );
|
2015-10-24 19:57:33 +02:00
|
|
|
static void InputSourceDestroy( input_source_t * );
|
2008-12-01 23:16:39 +01:00
|
|
|
static void InputSourceMeta( input_thread_t *, input_source_t *, vlc_meta_t * );
|
|
|
|
|
2007-06-04 00:40:17 +02:00
|
|
|
/* TODO */
|
|
|
|
//static void InputGetAttachments( input_thread_t *, input_source_t * );
|
2015-02-21 18:21:39 +01:00
|
|
|
static void SlaveDemux( input_thread_t *p_input );
|
2004-06-25 00:21:36 +02:00
|
|
|
static void SlaveSeek( input_thread_t *p_input );
|
2003-09-12 20:34:45 +02:00
|
|
|
|
2007-06-04 00:40:17 +02:00
|
|
|
static void InputMetaUser( input_thread_t *p_input, vlc_meta_t *p_meta );
|
2014-08-15 19:16:58 +02:00
|
|
|
static void InputUpdateMeta( input_thread_t *p_input, demux_t *p_demux );
|
2008-12-13 01:17:58 +01:00
|
|
|
static void InputGetExtraFiles( input_thread_t *p_input,
|
|
|
|
int *pi_list, char ***pppsz_list,
|
2021-09-15 17:37:28 +02:00
|
|
|
const char **psz_access, const char *mrl );
|
2004-06-29 00:49:43 +02:00
|
|
|
|
2020-11-04 10:24:25 +01:00
|
|
|
static void AppendAttachment(input_thread_t* p_input,
|
2020-11-04 13:26:19 +01:00
|
|
|
int i_new, input_attachment_t **pp_new);
|
2007-10-08 20:30:11 +02:00
|
|
|
|
2016-06-07 17:19:19 +02:00
|
|
|
#define SLAVE_ADD_NOFLAG 0
|
|
|
|
#define SLAVE_ADD_FORCED (1<<0)
|
|
|
|
#define SLAVE_ADD_CANFAIL (1<<1)
|
|
|
|
#define SLAVE_ADD_SET_TIME (1<<2)
|
2008-09-18 20:15:29 +02:00
|
|
|
|
2016-06-07 17:19:19 +02:00
|
|
|
static int input_SlaveSourceAdd( input_thread_t *, enum slave_type,
|
|
|
|
const char *, unsigned );
|
2016-03-25 13:56:11 +01:00
|
|
|
static char *input_SubtitleFile2Uri( input_thread_t *, const char * );
|
2019-08-13 17:57:39 +02:00
|
|
|
static void input_ChangeState( input_thread_t *p_input, int i_state, vlc_tick_t ); /* TODO fix name */
|
2008-11-20 21:49:51 +01:00
|
|
|
|
2009-05-08 02:03:05 +02:00
|
|
|
/**
|
|
|
|
* Start a input_thread_t created by input_Create.
|
|
|
|
*
|
|
|
|
* You must not start an already running input_thread_t.
|
|
|
|
*
|
|
|
|
* \param the input thread to start
|
|
|
|
*/
|
|
|
|
int input_Start( input_thread_t *p_input )
|
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
input_thread_private_t *priv = input_priv(p_input);
|
2015-10-28 17:43:36 +01:00
|
|
|
void *(*func)(void *) = Run;
|
|
|
|
|
2019-06-26 13:35:06 +02:00
|
|
|
if( priv->type == INPUT_TYPE_PREPARSING )
|
2015-10-28 17:43:36 +01:00
|
|
|
func = Preparse;
|
|
|
|
|
2016-11-05 09:11:44 +01:00
|
|
|
assert( !priv->is_running );
|
2009-05-08 02:03:05 +02:00
|
|
|
/* Create thread and wait for its readiness. */
|
2022-04-25 18:11:51 +02:00
|
|
|
priv->is_running = !vlc_clone( &priv->thread, func, priv );
|
2016-11-05 09:11:44 +01:00
|
|
|
if( !priv->is_running )
|
2009-05-08 02:03:05 +02:00
|
|
|
{
|
|
|
|
msg_Err( p_input, "cannot create input thread" );
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
}
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Request a running input thread to stop and die
|
|
|
|
*
|
|
|
|
* \param p_input the input thread to stop
|
|
|
|
*/
|
2015-02-05 21:40:42 +01:00
|
|
|
void input_Stop( input_thread_t *p_input )
|
2009-05-08 02:03:05 +02:00
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
input_thread_private_t *sys = input_priv(p_input);
|
2015-06-07 21:01:07 +02:00
|
|
|
|
|
|
|
vlc_mutex_lock( &sys->lock_control );
|
|
|
|
/* Discard all pending controls */
|
2018-09-04 10:55:45 +02:00
|
|
|
for( size_t i = 0; i < sys->i_control; i++ )
|
2015-06-07 21:01:07 +02:00
|
|
|
{
|
|
|
|
input_control_t *ctrl = &sys->control[i];
|
2018-06-25 10:03:48 +02:00
|
|
|
ControlRelease( ctrl->i_type, &ctrl->param );
|
2015-06-07 21:01:07 +02:00
|
|
|
}
|
|
|
|
sys->i_control = 0;
|
|
|
|
sys->is_stopped = true;
|
|
|
|
vlc_cond_signal( &sys->wait_control );
|
|
|
|
vlc_mutex_unlock( &sys->lock_control );
|
2015-06-30 22:52:51 +02:00
|
|
|
vlc_interrupt_kill( &sys->interrupt );
|
2009-05-08 02:03:05 +02:00
|
|
|
}
|
|
|
|
|
2011-05-22 21:49:14 +02:00
|
|
|
/**
|
|
|
|
* Close an input
|
|
|
|
*
|
|
|
|
* It does not call input_Stop itself.
|
|
|
|
*/
|
2011-05-25 14:50:22 +02:00
|
|
|
void input_Close( input_thread_t *p_input )
|
2011-05-22 21:49:14 +02:00
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
if( input_priv(p_input)->is_running )
|
|
|
|
vlc_join( input_priv(p_input)->thread, NULL );
|
|
|
|
vlc_interrupt_deinit( &input_priv(p_input)->interrupt );
|
2019-05-31 15:26:56 +02:00
|
|
|
Destroy(p_input);
|
2011-05-22 21:49:14 +02:00
|
|
|
}
|
|
|
|
|
2018-06-25 10:03:49 +02:00
|
|
|
void input_SetTime( input_thread_t *p_input, vlc_tick_t i_time, bool b_fast )
|
|
|
|
{
|
|
|
|
input_control_param_t param;
|
|
|
|
|
|
|
|
param.time.i_val = i_time;
|
|
|
|
param.time.b_fast_seek = b_fast;
|
|
|
|
input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, ¶m );
|
|
|
|
}
|
|
|
|
|
2022-08-03 13:18:40 +02:00
|
|
|
void input_SetPosition( input_thread_t *p_input, double f_position, bool b_fast )
|
2018-06-25 10:03:49 +02:00
|
|
|
{
|
|
|
|
input_control_param_t param;
|
|
|
|
|
|
|
|
param.pos.f_val = f_position;
|
|
|
|
param.pos.b_fast_seek = b_fast;
|
|
|
|
input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION, ¶m );
|
|
|
|
}
|
|
|
|
|
2009-05-08 02:03:05 +02:00
|
|
|
/**
|
|
|
|
* Get the item from an input thread
|
|
|
|
* FIXME it does not increase ref count of the item.
|
|
|
|
* if it is used after p_input is destroyed nothing prevent it from
|
|
|
|
* being freed.
|
|
|
|
*/
|
|
|
|
input_item_t *input_GetItem( input_thread_t *p_input )
|
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
assert( p_input != NULL );
|
|
|
|
return input_priv(p_input)->p_item;
|
2009-05-08 02:03:05 +02:00
|
|
|
}
|
|
|
|
|
2019-06-26 14:48:21 +02:00
|
|
|
#undef input_Create
|
|
|
|
/**
|
|
|
|
* Create a new input_thread_t.
|
2004-06-22 21:29:57 +02:00
|
|
|
*
|
2019-06-26 14:48:21 +02:00
|
|
|
* You need to call input_Start on it when you are done
|
|
|
|
* adding callback on the variables/events you want to monitor.
|
|
|
|
*
|
|
|
|
* \param p_parent a vlc_object
|
|
|
|
* \param p_item an input item
|
|
|
|
* \param p_resource an optional input ressource
|
|
|
|
* \return a pointer to the spawned input thread
|
|
|
|
*/
|
|
|
|
input_thread_t *input_Create( vlc_object_t *p_parent,
|
|
|
|
input_thread_events_cb events_cb, void *events_data,
|
|
|
|
input_item_t *p_item, enum input_type type,
|
|
|
|
input_resource_t *p_resource,
|
|
|
|
vlc_renderer_item_t *p_renderer )
|
1999-08-08 14:42:54 +02:00
|
|
|
{
|
2000-01-20 17:12:01 +01:00
|
|
|
/* Allocate descriptor */
|
2016-11-05 09:11:44 +01:00
|
|
|
input_thread_private_t *priv;
|
|
|
|
|
|
|
|
priv = vlc_custom_create( p_parent, sizeof( *priv ), "input" );
|
|
|
|
if( unlikely(priv == NULL) )
|
2002-06-07 16:30:41 +02:00
|
|
|
return NULL;
|
2008-04-15 19:30:29 +02:00
|
|
|
|
2020-02-26 13:09:26 +01:00
|
|
|
priv->master = InputSourceNew( NULL );
|
2020-02-27 18:17:19 +01:00
|
|
|
if( !priv->master )
|
|
|
|
{
|
|
|
|
free( priv );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-11-05 09:11:44 +01:00
|
|
|
input_thread_t *p_input = &priv->input;
|
|
|
|
|
2008-04-15 19:30:29 +02:00
|
|
|
char * psz_name = input_item_GetName( p_item );
|
2019-06-26 13:35:06 +02:00
|
|
|
const char *type_str;
|
|
|
|
switch (type)
|
2019-03-21 10:05:48 +01:00
|
|
|
{
|
2019-06-26 13:35:06 +02:00
|
|
|
case INPUT_TYPE_PREPARSING:
|
|
|
|
type_str = "preparsing ";
|
2019-03-21 10:05:48 +01:00
|
|
|
break;
|
2019-06-26 13:35:06 +02:00
|
|
|
case INPUT_TYPE_THUMBNAILING:
|
|
|
|
type_str = "thumbnailing ";
|
2019-03-21 10:06:15 +01:00
|
|
|
break;
|
2019-03-21 10:05:48 +01:00
|
|
|
default:
|
2019-06-26 13:35:06 +02:00
|
|
|
type_str = "";
|
2019-03-21 10:05:48 +01:00
|
|
|
break;
|
|
|
|
}
|
2019-06-26 13:35:06 +02:00
|
|
|
msg_Dbg( p_input, "Creating an input for %s'%s'", type_str, psz_name);
|
2008-04-15 19:30:29 +02:00
|
|
|
free( psz_name );
|
|
|
|
|
2010-03-02 23:09:34 +01:00
|
|
|
/* Parse input options */
|
2015-03-30 20:08:45 +02:00
|
|
|
input_item_ApplyOptions( VLC_OBJECT(p_input), p_item );
|
2010-03-02 23:09:34 +01:00
|
|
|
|
2004-06-22 21:29:57 +02:00
|
|
|
/* Init Common fields */
|
core: first cleaning of input_thread_t variables/event
Currently, the input_thread_t is controllable by either input_Control, specific
functions, by variables or by the 3 previous solutions.
The goal of this commit is to remove variables usage when it's not necessary.
This commit doesn't remove variables that should be used to pass users settings
(cf. input_ConfigVarInit).
The "intf-event" callback is replaced by the new callback
input_thread_events_cb that pass a new event: struct vlc_input_event. There can
be only one listener: the creator of the input_thread_t. In the future, the new
vlc input controller will receive these events and forward them to all
listeners.
In the meantime, I added input_LegacyVarInit, input_LegacyVarStop, and
input_LegacyEvents, 3 helpers functions that reproduce the legacy variable
behavior (transform new vlc_input_event to old intf-event events). These 3
functions are meant to be removed for 4.0 release (when vlc input controller is
added).
For now, the playlist, the media_player, VLM and modules still use the legacy
variables.
2018-07-06 13:43:55 +02:00
|
|
|
priv->events_cb = events_cb;
|
|
|
|
priv->events_data = events_data;
|
2019-06-26 13:35:06 +02:00
|
|
|
priv->type = type;
|
2016-11-05 09:11:44 +01:00
|
|
|
priv->i_start = 0;
|
|
|
|
priv->i_stop = 0;
|
|
|
|
priv->i_title_offset = input_priv(p_input)->i_seekpoint_offset = 0;
|
|
|
|
priv->i_state = INIT_S;
|
|
|
|
priv->is_running = false;
|
|
|
|
priv->is_stopped = false;
|
|
|
|
priv->b_recording = false;
|
2019-02-15 15:38:39 +01:00
|
|
|
priv->rate = 1.f;
|
2019-09-10 18:28:04 +02:00
|
|
|
priv->normal_time = VLC_TICK_0;
|
2016-11-05 09:11:44 +01:00
|
|
|
TAB_INIT( priv->i_attachment, priv->attachment );
|
|
|
|
priv->p_sout = NULL;
|
2019-06-26 13:35:06 +02:00
|
|
|
priv->b_out_pace_control = priv->type == INPUT_TYPE_THUMBNAILING;
|
|
|
|
priv->p_renderer = p_renderer && priv->type != INPUT_TYPE_PREPARSING ?
|
2018-01-15 10:15:00 +01:00
|
|
|
vlc_renderer_item_hold( p_renderer ) : NULL;
|
2004-06-22 21:29:57 +02:00
|
|
|
|
2017-07-24 19:17:29 +02:00
|
|
|
priv->viewpoint_changed = false;
|
|
|
|
/* Fetch the viewpoint from the mediaplayer or the playlist if any */
|
2016-11-10 18:24:18 +01:00
|
|
|
vlc_viewpoint_t *p_viewpoint = var_InheritAddress( p_input, "viewpoint" );
|
2017-07-24 19:17:29 +02:00
|
|
|
if (p_viewpoint != NULL)
|
2016-11-10 18:24:18 +01:00
|
|
|
priv->viewpoint = *p_viewpoint;
|
|
|
|
else
|
|
|
|
vlc_viewpoint_init( &priv->viewpoint );
|
|
|
|
|
2017-04-09 16:23:17 +02:00
|
|
|
input_item_Hold( p_item ); /* Released in Destructor() */
|
2016-11-05 09:11:44 +01:00
|
|
|
priv->p_item = p_item;
|
2008-12-02 19:16:17 +01:00
|
|
|
|
|
|
|
/* Init Input fields */
|
2007-06-04 00:40:17 +02:00
|
|
|
vlc_mutex_lock( &p_item->lock );
|
2006-10-01 16:24:44 +02:00
|
|
|
|
|
|
|
if( !p_item->p_stats )
|
2017-12-11 20:01:32 +01:00
|
|
|
p_item->p_stats = calloc( 1, sizeof(*p_item->p_stats) );
|
2015-03-24 17:22:19 +01:00
|
|
|
|
|
|
|
/* setup the preparse depth of the item
|
|
|
|
* if we are preparsing, use the i_preparse_depth of the parent item */
|
2019-06-26 13:35:06 +02:00
|
|
|
if( priv->type == INPUT_TYPE_PREPARSING
|
|
|
|
|| priv->type == INPUT_TYPE_THUMBNAILING )
|
2019-06-26 17:01:59 +02:00
|
|
|
{
|
|
|
|
p_input->obj.logger = NULL;
|
|
|
|
p_input->obj.no_interact = true;
|
|
|
|
}
|
|
|
|
else
|
2015-03-24 17:22:19 +01:00
|
|
|
{
|
|
|
|
char *psz_rec = var_InheritString( p_parent, "recursive" );
|
|
|
|
|
|
|
|
if( psz_rec != NULL )
|
|
|
|
{
|
|
|
|
if ( !strcasecmp( psz_rec, "none" ) )
|
|
|
|
p_item->i_preparse_depth = 0;
|
|
|
|
else if ( !strcasecmp( psz_rec, "collapse" ) )
|
|
|
|
p_item->i_preparse_depth = 1;
|
|
|
|
else
|
|
|
|
p_item->i_preparse_depth = -1; /* default is expand */
|
|
|
|
free (psz_rec);
|
|
|
|
} else
|
|
|
|
p_item->i_preparse_depth = -1;
|
|
|
|
}
|
2016-02-03 17:47:16 +01:00
|
|
|
|
|
|
|
/* Make sure the interaction option is honored */
|
|
|
|
if( !var_InheritBool( p_input, "interact" ) )
|
2019-02-20 17:11:48 +01:00
|
|
|
p_input->obj.no_interact = true;
|
2016-02-03 17:47:16 +01:00
|
|
|
else if( p_item->b_preparse_interact )
|
|
|
|
{
|
|
|
|
/* If true, this item was asked explicitly to interact with the user
|
2016-06-01 11:59:09 +02:00
|
|
|
* (via libvlc_MetadataRequest). Sub items created from this input won't
|
2016-02-03 17:47:16 +01:00
|
|
|
* have this flag and won't interact with the user */
|
2019-02-20 17:11:48 +01:00
|
|
|
p_input->obj.no_interact = false;
|
2016-02-03 17:47:16 +01:00
|
|
|
}
|
|
|
|
|
2007-06-04 00:40:17 +02:00
|
|
|
vlc_mutex_unlock( &p_item->lock );
|
2006-01-11 21:00:58 +01:00
|
|
|
|
2004-06-25 00:21:36 +02:00
|
|
|
/* No slave */
|
2016-11-05 09:11:44 +01:00
|
|
|
priv->i_slave = 0;
|
|
|
|
priv->slave = NULL;
|
2004-06-25 00:21:36 +02:00
|
|
|
|
2008-12-23 19:45:59 +01:00
|
|
|
/* */
|
2009-03-01 09:40:11 +01:00
|
|
|
if( p_resource )
|
2016-11-05 09:11:44 +01:00
|
|
|
priv->p_resource = input_resource_Hold( p_resource );
|
2008-12-27 11:44:24 +01:00
|
|
|
else
|
2019-06-27 10:00:32 +02:00
|
|
|
priv->p_resource = input_resource_New( VLC_OBJECT( p_input ) );
|
2016-11-05 09:11:44 +01:00
|
|
|
input_resource_SetInput( priv->p_resource, p_input );
|
2008-12-23 19:45:59 +01:00
|
|
|
|
2004-06-22 21:29:57 +02:00
|
|
|
/* Init control buffer */
|
2016-11-05 09:11:44 +01:00
|
|
|
vlc_mutex_init( &priv->lock_control );
|
|
|
|
vlc_cond_init( &priv->wait_control );
|
|
|
|
priv->i_control = 0;
|
|
|
|
vlc_interrupt_init(&priv->interrupt);
|
2004-03-31 22:52:31 +02:00
|
|
|
|
2004-06-22 21:29:57 +02:00
|
|
|
/* Create Object Variables for private use only */
|
|
|
|
input_ConfigVarInit( p_input );
|
1999-08-08 14:42:54 +02:00
|
|
|
|
2019-04-16 18:10:52 +02:00
|
|
|
priv->b_low_delay = var_InheritBool( p_input, "low-delay" );
|
2020-08-12 13:26:07 +02:00
|
|
|
priv->i_jitter_max = VLC_TICK_FROM_MS(var_InheritInteger( p_input, "clock-jitter" ));
|
2019-04-16 18:10:52 +02:00
|
|
|
|
2005-04-26 09:17:42 +02:00
|
|
|
/* Remove 'Now playing' info as it is probably outdated */
|
2007-08-15 06:33:57 +02:00
|
|
|
input_item_SetNowPlaying( p_item, NULL );
|
2014-12-17 14:26:50 +01:00
|
|
|
input_item_SetESNowPlaying( p_item, NULL );
|
2005-11-09 14:44:49 +01:00
|
|
|
|
2007-02-28 23:45:02 +01:00
|
|
|
/* */
|
2019-06-26 13:35:06 +02:00
|
|
|
if( priv->type != INPUT_TYPE_PREPARSING && var_InheritBool( p_input, "stats" ) )
|
2017-12-12 18:32:46 +01:00
|
|
|
priv->stats = input_stats_Create();
|
|
|
|
else
|
|
|
|
priv->stats = NULL;
|
2008-03-28 10:39:37 +01:00
|
|
|
|
2019-06-26 13:35:06 +02:00
|
|
|
priv->p_es_out_display = input_EsOutNew( p_input, priv->master, priv->rate,
|
|
|
|
priv->type );
|
2020-02-26 14:13:23 +01:00
|
|
|
if( !priv->p_es_out_display )
|
|
|
|
{
|
|
|
|
Destroy( p_input );
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-11-05 09:11:44 +01:00
|
|
|
priv->p_es_out = NULL;
|
2010-01-31 00:27:55 +01:00
|
|
|
|
2005-11-09 14:44:49 +01:00
|
|
|
return p_input;
|
|
|
|
}
|
|
|
|
|
2019-05-31 15:26:56 +02:00
|
|
|
static void Destroy(input_thread_t *input)
|
2019-03-16 08:24:35 +01:00
|
|
|
{
|
2019-03-16 09:36:13 +01:00
|
|
|
input_thread_private_t *priv = input_priv(input);
|
|
|
|
|
2019-03-16 09:42:53 +01:00
|
|
|
#ifndef NDEBUG
|
|
|
|
char *name = input_item_GetName(priv->p_item);
|
|
|
|
msg_Dbg(input, "destroying input for '%s'", name);
|
|
|
|
free(name);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (priv->p_renderer != NULL)
|
|
|
|
vlc_renderer_item_release(priv->p_renderer);
|
|
|
|
if (priv->p_es_out_display != NULL)
|
|
|
|
es_out_Delete(priv->p_es_out_display);
|
|
|
|
|
|
|
|
if (priv->p_resource != NULL)
|
|
|
|
input_resource_Release(priv->p_resource);
|
|
|
|
|
2020-02-27 18:17:19 +01:00
|
|
|
input_source_Release(priv->master);
|
2019-03-16 09:42:53 +01:00
|
|
|
input_item_Release(priv->p_item);
|
|
|
|
|
|
|
|
if (priv->stats != NULL)
|
|
|
|
input_stats_Destroy(priv->stats);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < priv->i_control; i++)
|
|
|
|
{
|
|
|
|
input_control_t *ctrl = &priv->control[i];
|
|
|
|
|
|
|
|
ControlRelease(ctrl->i_type, &ctrl->param);
|
|
|
|
}
|
|
|
|
|
2019-03-16 09:36:13 +01:00
|
|
|
vlc_object_delete(VLC_OBJECT(input));
|
2019-03-16 08:24:35 +01:00
|
|
|
}
|
|
|
|
|
2000-02-13 05:31:35 +01:00
|
|
|
/*****************************************************************************
|
2004-06-22 21:29:57 +02:00
|
|
|
* Run: main thread loop
|
2005-11-09 14:44:49 +01:00
|
|
|
* This is the "normal" thread that spawns the input processing chain,
|
|
|
|
* reads the stream, cleans up and waits
|
2000-02-13 05:31:35 +01:00
|
|
|
*****************************************************************************/
|
2016-11-05 09:11:44 +01:00
|
|
|
static void *Run( void *data )
|
1999-08-08 14:42:54 +02:00
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
input_thread_private_t *priv = data;
|
|
|
|
input_thread_t *p_input = &priv->input;
|
2008-08-05 21:12:27 +02:00
|
|
|
|
2020-11-10 08:51:22 +01:00
|
|
|
vlc_thread_set_name("vlc-input");
|
|
|
|
|
2016-11-05 09:11:44 +01:00
|
|
|
vlc_interrupt_set(&priv->interrupt);
|
2015-06-30 22:52:51 +02:00
|
|
|
|
2015-02-05 21:30:36 +01:00
|
|
|
if( !Init( p_input ) )
|
|
|
|
{
|
|
|
|
MainLoop( p_input, true ); /* FIXME it can be wrong (like with VLM) */
|
2008-09-07 22:34:07 +02:00
|
|
|
|
2015-02-05 21:30:36 +01:00
|
|
|
/* Clean up */
|
|
|
|
End( p_input );
|
|
|
|
}
|
2009-03-13 00:29:19 +01:00
|
|
|
|
2009-01-12 20:20:37 +01:00
|
|
|
input_SendEventDead( p_input );
|
2008-08-07 20:34:04 +02:00
|
|
|
return NULL;
|
2005-11-09 14:44:49 +01:00
|
|
|
}
|
|
|
|
|
2016-11-05 09:11:44 +01:00
|
|
|
static void *Preparse( void *data )
|
2015-10-28 17:43:36 +01:00
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
input_thread_private_t *priv = data;
|
|
|
|
input_thread_t *p_input = &priv->input;
|
2015-10-28 17:43:36 +01:00
|
|
|
|
2020-11-10 08:51:22 +01:00
|
|
|
vlc_thread_set_name("vlc-preparse");
|
|
|
|
|
2016-11-05 09:11:44 +01:00
|
|
|
vlc_interrupt_set(&priv->interrupt);
|
2015-10-28 17:43:36 +01:00
|
|
|
|
|
|
|
if( !Init( p_input ) )
|
|
|
|
{ /* if the demux is a playlist, call Mainloop that will call
|
|
|
|
* demux_Demux in order to fetch sub items */
|
2016-11-05 09:11:44 +01:00
|
|
|
if ( input_item_ShouldPreparseSubItems( priv->p_item )
|
2020-09-27 12:29:01 +02:00
|
|
|
&& priv->master->p_demux->pf_readdir != NULL )
|
2015-10-28 17:43:36 +01:00
|
|
|
MainLoop( p_input, false );
|
|
|
|
End( p_input );
|
|
|
|
}
|
|
|
|
|
|
|
|
input_SendEventDead( p_input );
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-06-07 21:40:43 +02:00
|
|
|
bool input_Stopped( input_thread_t *input )
|
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
input_thread_private_t *sys = input_priv(input);
|
2015-06-07 21:40:43 +02:00
|
|
|
bool ret;
|
|
|
|
|
|
|
|
vlc_mutex_lock( &sys->lock_control );
|
|
|
|
ret = sys->is_stopped;
|
|
|
|
vlc_mutex_unlock( &sys->lock_control );
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2005-11-09 14:44:49 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* Main loop: Fill buffers from access, and demux
|
|
|
|
*****************************************************************************/
|
2008-09-07 21:58:43 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* MainLoopDemux
|
|
|
|
* It asks the demuxer to demux some data
|
|
|
|
*/
|
2015-11-04 21:45:19 +01:00
|
|
|
static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed )
|
2005-11-09 14:44:49 +01:00
|
|
|
{
|
2018-07-20 10:05:16 +02:00
|
|
|
input_thread_private_t* p_priv = input_priv(p_input);
|
|
|
|
demux_t *p_demux = p_priv->master->p_demux;
|
2018-07-21 19:00:19 +02:00
|
|
|
int i_ret = VLC_DEMUXER_SUCCESS;
|
2007-02-28 23:45:02 +01:00
|
|
|
|
2008-09-07 21:58:43 +02:00
|
|
|
*pb_changed = false;
|
2008-04-15 19:30:29 +02:00
|
|
|
|
2018-07-21 19:00:19 +02:00
|
|
|
if( p_priv->i_stop > 0 )
|
|
|
|
{
|
2019-08-29 11:33:43 +02:00
|
|
|
vlc_tick_t i_time;
|
|
|
|
if( demux_Control( p_demux, DEMUX_GET_TIME, &i_time ) )
|
|
|
|
i_time = VLC_TICK_INVALID;
|
2018-07-21 19:00:19 +02:00
|
|
|
|
2019-08-29 11:33:43 +02:00
|
|
|
if( p_priv->i_stop <= i_time )
|
2018-07-21 19:00:19 +02:00
|
|
|
i_ret = VLC_DEMUXER_EOF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( i_ret == VLC_DEMUXER_SUCCESS )
|
2016-06-07 11:15:15 +02:00
|
|
|
i_ret = demux_Demux( p_demux );
|
2008-09-07 21:58:43 +02:00
|
|
|
|
2016-03-30 08:55:47 +02:00
|
|
|
i_ret = i_ret > 0 ? VLC_DEMUXER_SUCCESS : ( i_ret < 0 ? VLC_DEMUXER_EGENERIC : VLC_DEMUXER_EOF);
|
|
|
|
|
|
|
|
if( i_ret == VLC_DEMUXER_SUCCESS )
|
2001-05-31 03:37:08 +02:00
|
|
|
{
|
2016-06-09 19:58:55 +02:00
|
|
|
if( demux_TestAndClearFlags( p_demux, INPUT_UPDATE_TITLE_LIST ) )
|
|
|
|
UpdateTitleListfromDemux( p_input );
|
|
|
|
|
2018-07-20 10:05:16 +02:00
|
|
|
if( p_priv->master->b_title_demux )
|
2008-09-07 21:58:43 +02:00
|
|
|
{
|
2016-06-09 19:58:55 +02:00
|
|
|
i_ret = UpdateTitleSeekpointFromDemux( p_input );
|
|
|
|
*pb_changed = true;
|
2008-09-07 21:58:43 +02:00
|
|
|
}
|
2016-06-09 19:58:55 +02:00
|
|
|
|
|
|
|
UpdateGenericFromDemux( p_input );
|
2008-09-07 21:58:43 +02:00
|
|
|
}
|
2001-04-10 19:47:05 +02:00
|
|
|
|
2016-03-30 08:55:47 +02:00
|
|
|
if( i_ret == VLC_DEMUXER_EOF )
|
2008-09-07 21:58:43 +02:00
|
|
|
{
|
2009-06-09 21:21:59 +02:00
|
|
|
msg_Dbg( p_input, "EOF reached" );
|
2018-07-20 10:05:16 +02:00
|
|
|
p_priv->master->b_eof = true;
|
|
|
|
es_out_Eos(p_priv->p_es_out);
|
2008-09-07 21:58:43 +02:00
|
|
|
}
|
2016-03-30 08:55:47 +02:00
|
|
|
else if( i_ret == VLC_DEMUXER_EGENERIC )
|
2008-09-07 21:58:43 +02:00
|
|
|
{
|
2019-08-13 17:57:39 +02:00
|
|
|
input_ChangeState( p_input, ERROR_S, VLC_TICK_INVALID );
|
2008-09-07 21:58:43 +02:00
|
|
|
}
|
2018-07-20 10:05:16 +02:00
|
|
|
else if( p_priv->i_slave > 0 )
|
2015-02-21 18:21:39 +01:00
|
|
|
SlaveDemux( p_input );
|
2008-09-07 21:58:43 +02:00
|
|
|
}
|
|
|
|
|
2015-11-04 21:45:19 +01:00
|
|
|
static int MainLoopTryRepeat( input_thread_t *p_input )
|
2009-06-09 21:21:59 +02:00
|
|
|
{
|
|
|
|
int i_repeat = var_GetInteger( p_input, "input-repeat" );
|
2015-04-14 17:16:53 +02:00
|
|
|
if( i_repeat <= 0 )
|
2009-06-09 21:21:59 +02:00
|
|
|
return VLC_EGENERIC;
|
|
|
|
|
|
|
|
vlc_value_t val;
|
|
|
|
|
|
|
|
msg_Dbg( p_input, "repeating the same input (%d)", i_repeat );
|
|
|
|
if( i_repeat > 0 )
|
|
|
|
{
|
|
|
|
i_repeat--;
|
|
|
|
var_SetInteger( p_input, "input-repeat", i_repeat );
|
|
|
|
}
|
|
|
|
|
2018-06-25 10:03:49 +02:00
|
|
|
input_thread_private_t *priv = input_priv(p_input);
|
2009-06-09 21:21:59 +02:00
|
|
|
/* Seek to start title/seekpoint */
|
2018-06-25 10:03:49 +02:00
|
|
|
val.i_int = priv->master->i_title_start - priv->master->i_title_offset;
|
|
|
|
if( val.i_int < 0 || val.i_int >= priv->master->i_title )
|
2009-06-09 21:21:59 +02:00
|
|
|
val.i_int = 0;
|
2018-06-25 10:03:48 +02:00
|
|
|
input_ControlPushHelper( p_input,
|
2009-06-09 21:21:59 +02:00
|
|
|
INPUT_CONTROL_SET_TITLE, &val );
|
|
|
|
|
2018-06-25 10:03:49 +02:00
|
|
|
val.i_int = priv->master->i_seekpoint_start -
|
|
|
|
priv->master->i_seekpoint_offset;
|
2009-06-09 21:21:59 +02:00
|
|
|
if( val.i_int > 0 /* TODO: check upper boundary */ )
|
2018-06-25 10:03:48 +02:00
|
|
|
input_ControlPushHelper( p_input,
|
2009-06-09 21:21:59 +02:00
|
|
|
INPUT_CONTROL_SET_SEEKPOINT, &val );
|
|
|
|
|
|
|
|
/* Seek to start position */
|
2018-06-25 10:03:49 +02:00
|
|
|
if( priv->i_start > 0 )
|
|
|
|
input_SetTime( p_input, priv->i_start, false );
|
2009-06-09 21:21:59 +02:00
|
|
|
else
|
2018-06-25 10:03:49 +02:00
|
|
|
input_SetPosition( p_input, 0.0f, false );
|
2009-06-09 21:21:59 +02:00
|
|
|
|
|
|
|
return VLC_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2008-09-07 21:58:43 +02:00
|
|
|
/**
|
2015-02-21 15:14:53 +01:00
|
|
|
* Update timing infos and statistics.
|
2008-09-07 21:58:43 +02:00
|
|
|
*/
|
2015-02-21 15:14:53 +01:00
|
|
|
static void MainLoopStatistics( input_thread_t *p_input )
|
2008-09-07 21:58:43 +02:00
|
|
|
{
|
2017-12-12 17:26:42 +01:00
|
|
|
input_thread_private_t *priv = input_priv(p_input);
|
2008-11-29 01:16:51 +01:00
|
|
|
double f_position = 0.0;
|
2019-08-29 11:31:59 +02:00
|
|
|
vlc_tick_t i_time;
|
|
|
|
vlc_tick_t i_length;
|
2008-09-07 21:58:43 +02:00
|
|
|
|
|
|
|
/* update input status variables */
|
2017-12-12 17:26:42 +01:00
|
|
|
if( demux_Control( priv->master->p_demux,
|
2008-11-29 01:16:51 +01:00
|
|
|
DEMUX_GET_POSITION, &f_position ) )
|
|
|
|
f_position = 0.0;
|
2008-09-07 21:58:43 +02:00
|
|
|
|
2017-12-12 17:26:42 +01:00
|
|
|
if( demux_Control( priv->master->p_demux, DEMUX_GET_TIME, &i_time ) )
|
2019-08-29 11:31:59 +02:00
|
|
|
i_time = VLC_TICK_INVALID;
|
2008-11-20 21:49:51 +01:00
|
|
|
|
2017-12-12 17:26:42 +01:00
|
|
|
if( demux_Control( priv->master->p_demux, DEMUX_GET_LENGTH, &i_length ) )
|
2020-12-03 16:07:46 +01:00
|
|
|
i_length = 0;
|
2008-09-07 21:58:43 +02:00
|
|
|
|
2019-09-10 18:28:04 +02:00
|
|
|
/* In case of failure (not implemented or in case of seek), use the last
|
|
|
|
* normal_time value (that is VLC_TICK_0 by default). */
|
2023-02-02 13:49:21 +01:00
|
|
|
if (demux_Control( priv->master->p_demux, DEMUX_GET_NORMAL_TIME, &priv->normal_time ) != VLC_SUCCESS)
|
|
|
|
priv->normal_time = VLC_TICK_0;
|
2019-09-10 18:28:04 +02:00
|
|
|
|
|
|
|
es_out_SetTimes( priv->p_es_out, f_position, i_time, priv->normal_time,
|
|
|
|
i_length );
|
2008-12-02 20:08:40 +01:00
|
|
|
|
2023-02-22 16:45:52 +01:00
|
|
|
if (priv->stats != NULL)
|
|
|
|
{
|
|
|
|
struct input_stats_t new_stats;
|
|
|
|
input_stats_Compute(priv->stats, &new_stats);
|
2018-09-06 10:13:32 +02:00
|
|
|
|
2023-02-22 16:45:52 +01:00
|
|
|
vlc_mutex_lock(&priv->p_item->lock);
|
2018-09-06 10:13:32 +02:00
|
|
|
*priv->p_item->p_stats = new_stats;
|
2023-02-22 16:45:52 +01:00
|
|
|
vlc_mutex_unlock(&priv->p_item->lock);
|
2017-12-11 20:01:32 +01:00
|
|
|
|
2023-02-22 16:45:52 +01:00
|
|
|
input_SendEventStatistics(p_input, &new_stats);
|
|
|
|
}
|
2008-09-07 21:58:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* MainLoop
|
|
|
|
* The main input loop.
|
|
|
|
*/
|
2009-09-14 23:22:49 +02:00
|
|
|
static void MainLoop( input_thread_t *p_input, bool b_interactive )
|
2008-09-07 21:58:43 +02:00
|
|
|
{
|
2018-06-22 13:19:24 +02:00
|
|
|
vlc_tick_t i_intf_update = 0;
|
|
|
|
vlc_tick_t i_last_seek_mdate = 0;
|
2015-05-23 20:34:31 +02:00
|
|
|
|
|
|
|
if( b_interactive && var_InheritBool( p_input, "start-paused" ) )
|
2018-06-20 08:37:11 +02:00
|
|
|
ControlPause( p_input, vlc_tick_now() );
|
2015-05-23 20:34:31 +02:00
|
|
|
|
2009-09-14 23:22:49 +02:00
|
|
|
bool b_pause_after_eof = b_interactive &&
|
2016-11-17 21:31:48 +01:00
|
|
|
var_InheritBool( p_input, "play-and-pause" );
|
|
|
|
bool b_paused_at_eof = false;
|
2008-09-07 21:58:43 +02:00
|
|
|
|
2016-11-05 09:11:44 +01:00
|
|
|
demux_t *p_demux = input_priv(p_input)->master->p_demux;
|
2023-03-17 11:48:19 +01:00
|
|
|
const bool b_can_demux = p_demux->ops != NULL ?
|
|
|
|
(p_demux->ops->demux.demux != NULL || p_demux->ops->demux.readdir != NULL) :
|
|
|
|
(p_demux->pf_demux != NULL || p_demux->pf_readdir != NULL);
|
2016-06-07 11:15:13 +02:00
|
|
|
|
2016-11-05 09:11:44 +01:00
|
|
|
while( !input_Stopped( p_input ) && input_priv(p_input)->i_state != ERROR_S )
|
2008-09-07 21:58:43 +02:00
|
|
|
{
|
2018-06-22 13:19:24 +02:00
|
|
|
vlc_tick_t i_wakeup = -1;
|
2016-11-05 09:11:44 +01:00
|
|
|
bool b_paused = input_priv(p_input)->i_state == PAUSE_S;
|
|
|
|
/* FIXME if input_priv(p_input)->i_state == PAUSE_S the access/access_demux
|
2008-10-15 20:09:09 +02:00
|
|
|
* is paused -> this may cause problem with some of them
|
|
|
|
* The same problem can be seen when seeking while paused */
|
2015-02-21 15:27:48 +01:00
|
|
|
if( b_paused )
|
2016-11-05 09:11:44 +01:00
|
|
|
b_paused = !es_out_GetBuffering( input_priv(p_input)->p_es_out )
|
|
|
|
|| input_priv(p_input)->master->b_eof;
|
2008-10-10 00:36:49 +02:00
|
|
|
|
|
|
|
if( !b_paused )
|
2008-09-23 22:13:17 +02:00
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
if( !input_priv(p_input)->master->b_eof )
|
2008-11-02 19:00:22 +01:00
|
|
|
{
|
2015-02-21 16:35:59 +01:00
|
|
|
bool b_force_update = false;
|
2008-11-01 16:19:52 +01:00
|
|
|
|
2015-11-04 21:45:19 +01:00
|
|
|
MainLoopDemux( p_input, &b_force_update );
|
2015-02-21 16:35:59 +01:00
|
|
|
|
2016-06-07 11:15:13 +02:00
|
|
|
if( b_can_demux )
|
2016-11-05 09:11:44 +01:00
|
|
|
i_wakeup = es_out_GetWakeup( input_priv(p_input)->p_es_out );
|
2015-02-21 16:35:59 +01:00
|
|
|
if( b_force_update )
|
|
|
|
i_intf_update = 0;
|
2016-11-17 21:31:48 +01:00
|
|
|
|
|
|
|
b_paused_at_eof = false;
|
2008-11-02 19:00:22 +01:00
|
|
|
}
|
2016-11-05 09:11:44 +01:00
|
|
|
else if( !es_out_GetEmpty( input_priv(p_input)->p_es_out ) )
|
2008-11-02 19:00:22 +01:00
|
|
|
{
|
|
|
|
msg_Dbg( p_input, "waiting decoder fifos to empty" );
|
2018-06-20 08:37:11 +02:00
|
|
|
i_wakeup = vlc_tick_now() + INPUT_IDLE_SLEEP;
|
2008-11-02 19:00:22 +01:00
|
|
|
}
|
2009-12-26 15:18:06 +01:00
|
|
|
/* Pause after eof only if the input is pausable.
|
|
|
|
* This way we won't trigger timeshifting for nothing */
|
2021-04-27 13:33:21 +02:00
|
|
|
else if( b_pause_after_eof && input_priv(p_input)->master->b_can_pause )
|
2009-09-14 22:51:06 +02:00
|
|
|
{
|
2016-11-17 21:31:48 +01:00
|
|
|
if( b_paused_at_eof )
|
|
|
|
break;
|
|
|
|
|
2018-06-25 10:03:48 +02:00
|
|
|
input_control_param_t param;
|
|
|
|
param.val.i_int = PAUSE_S;
|
2015-02-21 15:27:48 +01:00
|
|
|
|
2009-09-14 22:51:06 +02:00
|
|
|
msg_Dbg( p_input, "pausing at EOF (pause after each)");
|
2018-06-25 10:03:48 +02:00
|
|
|
Control( p_input, INPUT_CONTROL_SET_STATE, param );
|
2009-09-14 22:51:06 +02:00
|
|
|
|
|
|
|
b_paused = true;
|
2016-11-17 21:31:48 +01:00
|
|
|
b_paused_at_eof = true;
|
2009-09-14 22:51:06 +02:00
|
|
|
}
|
2008-11-02 19:00:22 +01:00
|
|
|
else
|
|
|
|
{
|
2015-11-04 21:45:19 +01:00
|
|
|
if( MainLoopTryRepeat( p_input ) )
|
2009-06-09 21:21:59 +02:00
|
|
|
break;
|
2008-11-02 19:00:22 +01:00
|
|
|
}
|
2015-02-21 16:35:59 +01:00
|
|
|
|
|
|
|
/* Update interface and statistics */
|
2018-06-20 08:37:11 +02:00
|
|
|
vlc_tick_t now = vlc_tick_now();
|
2015-02-21 16:35:59 +01:00
|
|
|
if( now >= i_intf_update )
|
|
|
|
{
|
|
|
|
MainLoopStatistics( p_input );
|
2018-07-03 08:48:08 +02:00
|
|
|
i_intf_update = now + VLC_TICK_FROM_MS(250);
|
2015-02-21 16:35:59 +01:00
|
|
|
}
|
2008-09-23 22:13:17 +02:00
|
|
|
}
|
2008-09-07 22:19:33 +02:00
|
|
|
|
2015-02-21 19:18:30 +01:00
|
|
|
/* Handle control */
|
|
|
|
for( ;; )
|
|
|
|
{
|
2018-06-22 13:19:24 +02:00
|
|
|
vlc_tick_t i_deadline = i_wakeup;
|
2015-02-21 19:18:30 +01:00
|
|
|
|
|
|
|
/* Postpone seeking until ES buffering is complete or at most
|
|
|
|
* 125 ms. */
|
2016-11-05 09:11:44 +01:00
|
|
|
bool b_postpone = es_out_GetBuffering( input_priv(p_input)->p_es_out )
|
|
|
|
&& !input_priv(p_input)->master->b_eof;
|
2015-02-21 19:18:30 +01:00
|
|
|
if( b_postpone )
|
2008-09-23 22:13:17 +02:00
|
|
|
{
|
2018-06-20 08:37:11 +02:00
|
|
|
vlc_tick_t now = vlc_tick_now();
|
2015-02-21 19:18:30 +01:00
|
|
|
|
|
|
|
/* Recheck ES buffer level every 20 ms when seeking */
|
2018-07-03 08:48:08 +02:00
|
|
|
if( now < i_last_seek_mdate + VLC_TICK_FROM_MS(125)
|
|
|
|
&& (i_deadline < 0 || i_deadline > now + VLC_TICK_FROM_MS(20)) )
|
|
|
|
i_deadline = now + VLC_TICK_FROM_MS(20);
|
2015-02-21 19:18:30 +01:00
|
|
|
else
|
|
|
|
b_postpone = false;
|
|
|
|
}
|
2009-11-28 11:43:24 +01:00
|
|
|
|
2015-02-21 19:18:30 +01:00
|
|
|
int i_type;
|
2018-06-25 10:03:48 +02:00
|
|
|
input_control_param_t param;
|
2015-02-21 15:27:48 +01:00
|
|
|
|
2018-06-25 10:03:48 +02:00
|
|
|
if( ControlPop( p_input, &i_type, ¶m, i_deadline, b_postpone ) )
|
2015-02-21 19:18:30 +01:00
|
|
|
{
|
|
|
|
if( b_postpone )
|
|
|
|
continue;
|
|
|
|
break; /* Wake-up time reached */
|
|
|
|
}
|
2009-01-24 11:11:42 +01:00
|
|
|
|
2011-03-17 11:36:42 +01:00
|
|
|
#ifndef NDEBUG
|
2015-02-21 19:18:30 +01:00
|
|
|
msg_Dbg( p_input, "control type=%d", i_type );
|
2011-03-17 11:36:42 +01:00
|
|
|
#endif
|
2018-06-25 10:03:48 +02:00
|
|
|
if( Control( p_input, i_type, param ) )
|
2015-02-21 19:18:30 +01:00
|
|
|
{
|
|
|
|
if( ControlIsSeekRequest( i_type ) )
|
2018-06-20 08:37:11 +02:00
|
|
|
i_last_seek_mdate = vlc_tick_now();
|
2015-02-21 19:18:30 +01:00
|
|
|
i_intf_update = 0;
|
2008-09-23 22:13:17 +02:00
|
|
|
}
|
2001-06-12 20:16:49 +02:00
|
|
|
|
2009-07-15 18:04:51 +02:00
|
|
|
/* Update the wakeup time */
|
2008-09-25 20:06:47 +02:00
|
|
|
if( i_wakeup != 0 )
|
2016-11-05 09:11:44 +01:00
|
|
|
i_wakeup = es_out_GetWakeup( input_priv(p_input)->p_es_out );
|
2015-02-21 19:18:30 +01:00
|
|
|
}
|
2004-06-22 21:29:57 +02:00
|
|
|
}
|
1999-10-02 00:05:33 +02:00
|
|
|
}
|
|
|
|
|
2008-05-01 19:04:27 +02:00
|
|
|
#ifdef ENABLE_SOUT
|
2008-04-14 12:32:44 +02:00
|
|
|
static int InitSout( input_thread_t * p_input )
|
|
|
|
{
|
2016-11-05 10:22:30 +01:00
|
|
|
input_thread_private_t *priv = input_priv(p_input);
|
|
|
|
|
2019-06-26 13:35:06 +02:00
|
|
|
if( priv->type == INPUT_TYPE_PREPARSING )
|
2008-12-23 19:45:59 +01:00
|
|
|
return VLC_SUCCESS;
|
2008-04-14 12:32:44 +02:00
|
|
|
|
|
|
|
/* Find a usable sout and attach it to p_input */
|
2018-01-31 16:04:50 +01:00
|
|
|
char *psz = var_GetNonEmptyString( p_input, "sout" );
|
2017-07-04 16:30:26 +02:00
|
|
|
if( priv->p_renderer )
|
|
|
|
{
|
2018-01-31 16:04:50 +01:00
|
|
|
/* Keep sout if it comes from a renderer and if the user didn't touch
|
|
|
|
* the sout config */
|
|
|
|
bool keep_sout = psz == NULL;
|
|
|
|
free(psz);
|
|
|
|
|
2017-07-04 16:30:26 +02:00
|
|
|
const char *psz_renderer_sout = vlc_renderer_item_sout( priv->p_renderer );
|
|
|
|
if( asprintf( &psz, "#%s", psz_renderer_sout ) < 0 )
|
|
|
|
return VLC_ENOMEM;
|
2018-01-31 16:04:50 +01:00
|
|
|
if( keep_sout )
|
|
|
|
var_SetBool( p_input, "sout-keep", true );
|
2017-07-04 16:30:26 +02:00
|
|
|
}
|
2016-11-05 10:22:30 +01:00
|
|
|
if( psz && strncasecmp( priv->p_item->psz_uri, "vlc:", 4 ) )
|
2003-09-08 00:51:11 +02:00
|
|
|
{
|
2021-01-19 19:03:27 +01:00
|
|
|
priv->p_sout = input_resource_RequestSout( priv->p_resource, psz );
|
2016-11-05 10:22:30 +01:00
|
|
|
if( priv->p_sout == NULL )
|
2006-06-19 19:33:43 +02:00
|
|
|
{
|
2019-08-13 17:57:39 +02:00
|
|
|
input_ChangeState( p_input, ERROR_S, VLC_TICK_INVALID );
|
2008-12-23 19:45:59 +01:00
|
|
|
msg_Err( p_input, "cannot start stream output instance, " \
|
|
|
|
"aborting" );
|
|
|
|
free( psz );
|
|
|
|
return VLC_EGENERIC;
|
2003-09-08 00:51:11 +02:00
|
|
|
}
|
2001-10-02 18:46:59 +02:00
|
|
|
}
|
2008-12-23 19:45:59 +01:00
|
|
|
else
|
2004-04-04 16:34:36 +02:00
|
|
|
{
|
2021-01-19 18:39:47 +01:00
|
|
|
input_resource_TerminateSout( priv->p_resource );
|
2004-06-22 21:29:57 +02:00
|
|
|
}
|
2008-04-14 12:32:44 +02:00
|
|
|
free( psz );
|
2004-04-04 16:34:36 +02:00
|
|
|
|
2008-04-14 12:32:44 +02:00
|
|
|
return VLC_SUCCESS;
|
|
|
|
}
|
2008-05-01 19:04:27 +02:00
|
|
|
#endif
|
2004-06-25 00:21:36 +02:00
|
|
|
|
2021-04-27 13:46:29 +02:00
|
|
|
static void InitProperties( input_thread_t *input )
|
|
|
|
{
|
|
|
|
input_thread_private_t *priv = input_priv(input);
|
|
|
|
input_source_t *master = priv->master;
|
|
|
|
assert(master);
|
|
|
|
|
2021-12-15 15:25:39 +01:00
|
|
|
int capabilities = 0;
|
2021-04-27 13:46:29 +02:00
|
|
|
bool b_can_seek;
|
|
|
|
|
|
|
|
if( demux_Control( master->p_demux, DEMUX_CAN_SEEK, &b_can_seek ) )
|
|
|
|
b_can_seek = false;
|
|
|
|
if( b_can_seek )
|
2021-12-15 15:25:39 +01:00
|
|
|
capabilities |= VLC_INPUT_CAPABILITIES_SEEKABLE;
|
2021-04-27 13:46:29 +02:00
|
|
|
|
|
|
|
if( master->b_can_pause || !master->b_can_pace_control )
|
2021-12-15 15:25:39 +01:00
|
|
|
capabilities |= VLC_INPUT_CAPABILITIES_PAUSEABLE;
|
2021-04-27 13:46:29 +02:00
|
|
|
if( !master->b_can_pace_control || master->b_can_rate_control )
|
2021-12-15 15:25:39 +01:00
|
|
|
capabilities |= VLC_INPUT_CAPABILITIES_CHANGE_RATE;
|
2021-04-27 13:46:29 +02:00
|
|
|
if( !master->b_rescale_ts && !master->b_can_pace_control && master->b_can_rate_control )
|
2021-12-15 15:25:39 +01:00
|
|
|
capabilities |= VLC_INPUT_CAPABILITIES_REWINDABLE;
|
2021-04-27 13:46:29 +02:00
|
|
|
|
|
|
|
#ifdef ENABLE_SOUT
|
2021-12-15 15:25:39 +01:00
|
|
|
capabilities |= VLC_INPUT_CAPABILITIES_RECORDABLE;
|
2021-04-27 13:46:29 +02:00
|
|
|
#else
|
|
|
|
if( master->b_can_stream_record )
|
2021-12-15 15:25:39 +01:00
|
|
|
capabilities |= VLC_INPUT_CAPABILITIES_RECORDABLE;
|
2021-04-27 13:46:29 +02:00
|
|
|
#endif
|
|
|
|
|
2021-12-15 15:25:39 +01:00
|
|
|
input_SendEventCapabilities( input, capabilities );
|
2021-04-27 13:46:29 +02:00
|
|
|
|
|
|
|
int i_attachment;
|
|
|
|
input_attachment_t **attachment;
|
|
|
|
if( !demux_Control( master->p_demux, DEMUX_GET_ATTACHMENTS,
|
|
|
|
&attachment, &i_attachment ) )
|
|
|
|
{
|
|
|
|
vlc_mutex_lock( &priv->p_item->lock );
|
|
|
|
AppendAttachment( input, i_attachment, attachment );
|
|
|
|
vlc_mutex_unlock( &priv->p_item->lock );
|
|
|
|
}
|
|
|
|
|
|
|
|
int input_type;
|
|
|
|
if( !demux_Control( master->p_demux, DEMUX_GET_TYPE, &input_type ) )
|
|
|
|
{
|
|
|
|
vlc_mutex_lock( &priv->p_item->lock );
|
|
|
|
priv->p_item->i_type = input_type;
|
|
|
|
vlc_mutex_unlock( &priv->p_item->lock );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-11 17:50:09 +02:00
|
|
|
static void InitTitle( input_thread_t * p_input, bool had_titles )
|
2008-04-14 12:32:44 +02:00
|
|
|
{
|
2016-11-05 10:22:30 +01:00
|
|
|
input_thread_private_t *priv = input_priv(p_input);
|
|
|
|
input_source_t *p_master = priv->master;
|
2004-06-22 21:29:57 +02:00
|
|
|
|
2019-06-26 13:35:06 +02:00
|
|
|
if( priv->type == INPUT_TYPE_PREPARSING )
|
2008-12-01 23:52:02 +01:00
|
|
|
return;
|
2000-12-05 20:36:58 +01:00
|
|
|
|
2016-11-05 10:22:30 +01:00
|
|
|
vlc_mutex_lock( &priv->p_item->lock );
|
|
|
|
priv->i_title_offset = p_master->i_title_offset;
|
|
|
|
priv->i_seekpoint_offset = p_master->i_seekpoint_offset;
|
|
|
|
vlc_mutex_unlock( &priv->p_item->lock );
|
2018-09-11 17:50:09 +02:00
|
|
|
|
|
|
|
/* Send event only if the count is valid or if titles are gone */
|
|
|
|
if (had_titles || p_master->i_title > 0)
|
|
|
|
input_SendEventTitle( p_input, &(struct vlc_input_event_title) {
|
|
|
|
.action = VLC_INPUT_TITLE_NEW_LIST,
|
|
|
|
.list = {
|
|
|
|
.array = p_master->title,
|
|
|
|
.count = p_master->i_title,
|
|
|
|
},
|
|
|
|
});
|
2008-04-14 12:32:44 +02:00
|
|
|
}
|
2003-05-22 18:01:02 +02:00
|
|
|
|
2008-04-14 12:32:44 +02:00
|
|
|
static void StartTitle( input_thread_t * p_input )
|
|
|
|
{
|
2016-11-05 10:22:30 +01:00
|
|
|
input_thread_private_t *priv = input_priv(p_input);
|
2008-04-14 12:32:44 +02:00
|
|
|
vlc_value_t val;
|
2004-09-29 20:14:31 +02:00
|
|
|
|
2008-04-14 12:32:44 +02:00
|
|
|
/* Start title/chapter */
|
2016-11-05 10:22:30 +01:00
|
|
|
val.i_int = priv->master->i_title_start - priv->master->i_title_offset;
|
|
|
|
if( val.i_int > 0 && val.i_int < priv->master->i_title )
|
2018-06-25 10:03:48 +02:00
|
|
|
input_ControlPushHelper( p_input, INPUT_CONTROL_SET_TITLE, &val );
|
2008-12-01 23:52:02 +01:00
|
|
|
|
2016-11-05 10:22:30 +01:00
|
|
|
val.i_int = priv->master->i_seekpoint_start -
|
|
|
|
priv->master->i_seekpoint_offset;
|
2008-04-14 12:32:44 +02:00
|
|
|
if( val.i_int > 0 /* TODO: check upper boundary */ )
|
2018-06-25 10:03:48 +02:00
|
|
|
input_ControlPushHelper( p_input, INPUT_CONTROL_SET_SEEKPOINT, &val );
|
2008-04-14 12:32:44 +02:00
|
|
|
|
2008-12-01 23:52:02 +01:00
|
|
|
/* Start/stop/run time */
|
2022-08-24 21:07:49 +02:00
|
|
|
priv->i_start = llroundl(CLOCK_FREQ *
|
|
|
|
(double) var_GetFloat( p_input, "start-time" ));
|
|
|
|
priv->i_stop = llroundl(CLOCK_FREQ *
|
|
|
|
(double) var_GetFloat( p_input, "stop-time" ));
|
2016-11-05 10:22:30 +01:00
|
|
|
if( priv->i_stop <= 0 )
|
2007-08-22 22:19:23 +02:00
|
|
|
{
|
2022-08-24 21:07:49 +02:00
|
|
|
priv->i_stop = llroundl(CLOCK_FREQ *
|
|
|
|
(double) var_GetFloat( p_input, "run-time" ));
|
2016-11-05 10:22:30 +01:00
|
|
|
if( priv->i_stop < 0 )
|
2015-11-04 21:45:19 +01:00
|
|
|
{
|
|
|
|
msg_Warn( p_input, "invalid run-time ignored" );
|
2016-11-05 10:22:30 +01:00
|
|
|
priv->i_stop = 0;
|
2015-11-04 21:45:19 +01:00
|
|
|
}
|
|
|
|
else
|
2016-11-05 10:22:30 +01:00
|
|
|
priv->i_stop += priv->i_start;
|
2007-08-20 16:52:24 +02:00
|
|
|
}
|
2004-08-21 01:37:40 +02:00
|
|
|
|
2016-11-05 10:22:30 +01:00
|
|
|
if( priv->i_start > 0 )
|
2004-06-22 21:29:57 +02:00
|
|
|
{
|
2016-11-05 10:22:30 +01:00
|
|
|
msg_Dbg( p_input, "starting at time: %"PRId64"s",
|
2018-06-14 14:31:36 +02:00
|
|
|
SEC_FROM_VLC_TICK(priv->i_start) );
|
2004-06-22 21:29:57 +02:00
|
|
|
|
2018-06-25 10:03:49 +02:00
|
|
|
input_SetTime( p_input, priv->i_start, false );
|
2008-04-14 12:32:44 +02:00
|
|
|
}
|
2016-11-05 10:22:30 +01:00
|
|
|
if( priv->i_stop > 0 && priv->i_stop <= priv->i_start )
|
2008-04-14 12:32:44 +02:00
|
|
|
{
|
|
|
|
msg_Warn( p_input, "invalid stop-time ignored" );
|
2016-11-05 10:22:30 +01:00
|
|
|
priv->i_stop = 0;
|
2008-04-14 12:32:44 +02:00
|
|
|
}
|
2008-12-01 23:52:02 +01:00
|
|
|
}
|
2004-10-02 23:02:27 +02:00
|
|
|
|
2016-03-24 10:21:32 +01:00
|
|
|
static int SlaveCompare(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
const input_item_slave_t *p_slave0 = *((const input_item_slave_t **) a);
|
|
|
|
const input_item_slave_t *p_slave1 = *((const input_item_slave_t **) b);
|
|
|
|
|
|
|
|
if( p_slave0 == NULL || p_slave1 == NULL )
|
|
|
|
{
|
|
|
|
/* Put NULL (or rejected) subs at the end */
|
|
|
|
return p_slave0 == NULL ? 1 : p_slave1 == NULL ? -1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( p_slave0->i_priority > p_slave1->i_priority )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if( p_slave0->i_priority < p_slave1->i_priority )
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-03-24 10:22:28 +01:00
|
|
|
static bool SlaveExists( input_item_slave_t **pp_slaves, int i_slaves,
|
|
|
|
const char *psz_uri)
|
|
|
|
{
|
|
|
|
for( int i = 0; i < i_slaves; i++ )
|
|
|
|
{
|
|
|
|
if( pp_slaves[i] != NULL
|
|
|
|
&& !strcmp( pp_slaves[i]->psz_uri, psz_uri ) )
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-10-17 14:43:14 +02:00
|
|
|
static void RequestSubRate( input_thread_t *p_input, float f_slave_fps )
|
|
|
|
{
|
|
|
|
input_thread_private_t *priv = input_priv(p_input);
|
|
|
|
const float f_fps = input_priv(p_input)->master->f_fps;
|
|
|
|
if( f_fps > 1.f && f_slave_fps > 1.f )
|
2019-02-15 15:38:39 +01:00
|
|
|
priv->slave_subs_rate = f_fps / f_slave_fps;
|
|
|
|
else if ( priv->slave_subs_rate != 0 )
|
|
|
|
priv->slave_subs_rate = 1.f;
|
2018-10-17 14:43:14 +02:00
|
|
|
}
|
|
|
|
|
2016-03-25 11:37:33 +01:00
|
|
|
static void SetSubtitlesOptions( input_thread_t *p_input )
|
2008-12-01 23:52:02 +01:00
|
|
|
{
|
2008-04-14 12:32:44 +02:00
|
|
|
/* Get fps and set it if not already set */
|
2016-11-05 09:11:44 +01:00
|
|
|
const float f_fps = input_priv(p_input)->master->f_fps;
|
2014-08-13 20:02:24 +02:00
|
|
|
if( f_fps > 1.f )
|
2008-04-14 12:32:44 +02:00
|
|
|
{
|
2018-10-17 14:38:50 +02:00
|
|
|
var_SetFloat( p_input, "sub-original-fps", f_fps );
|
2018-10-17 14:43:14 +02:00
|
|
|
RequestSubRate( p_input, var_InheritFloat( p_input, "sub-fps" ) );
|
2008-04-14 12:32:44 +02:00
|
|
|
}
|
2016-03-25 11:37:33 +01:00
|
|
|
}
|
2008-04-14 12:32:44 +02:00
|
|
|
|
2021-09-01 11:12:23 +02:00
|
|
|
static enum slave_type DeduceSlaveType( input_thread_t *p_input,
|
|
|
|
const char *psz_uri )
|
|
|
|
{
|
|
|
|
vlc_url_t parsed_uri;
|
|
|
|
if( vlc_UrlParse( &parsed_uri, psz_uri ) != VLC_SUCCESS ||
|
|
|
|
parsed_uri.psz_path == NULL )
|
|
|
|
{
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum slave_type i_type;
|
|
|
|
if( !input_item_slave_GetType( parsed_uri.psz_path, &i_type ) )
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
vlc_UrlClean( &parsed_uri );
|
|
|
|
return i_type;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
msg_Dbg( p_input, "Can't deduce slave type of \"%s\" with file extension.",
|
|
|
|
psz_uri );
|
|
|
|
vlc_UrlClean( &parsed_uri );
|
|
|
|
return SLAVE_TYPE_GENERIC;
|
|
|
|
}
|
|
|
|
|
2016-06-07 13:44:09 +02:00
|
|
|
static void GetVarSlaves( input_thread_t *p_input,
|
|
|
|
input_item_slave_t ***ppp_slaves, int *p_slaves )
|
2016-06-07 13:44:50 +02:00
|
|
|
{
|
|
|
|
char *psz = var_GetNonEmptyString( p_input, "input-slave" );
|
|
|
|
if( !psz )
|
|
|
|
return;
|
|
|
|
|
2016-06-07 13:44:09 +02:00
|
|
|
input_item_slave_t **pp_slaves = *ppp_slaves;
|
|
|
|
int i_slaves = *p_slaves;
|
|
|
|
|
2016-06-07 13:44:50 +02:00
|
|
|
char *psz_org = psz;
|
|
|
|
while( psz && *psz )
|
|
|
|
{
|
|
|
|
while( *psz == ' ' || *psz == '#' )
|
|
|
|
psz++;
|
|
|
|
|
|
|
|
char *psz_delim = strchr( psz, '#' );
|
|
|
|
if( psz_delim )
|
|
|
|
*psz_delim++ = '\0';
|
|
|
|
|
|
|
|
if( *psz == 0 )
|
|
|
|
break;
|
|
|
|
|
|
|
|
char *uri = strstr(psz, "://")
|
|
|
|
? strdup( psz ) : vlc_path2uri( psz, NULL );
|
|
|
|
psz = psz_delim;
|
|
|
|
if( uri == NULL )
|
|
|
|
continue;
|
|
|
|
|
2021-09-01 11:12:23 +02:00
|
|
|
const enum slave_type i_type = DeduceSlaveType( p_input, uri );
|
2016-06-07 13:44:09 +02:00
|
|
|
input_item_slave_t *p_slave =
|
2021-03-30 15:29:53 +02:00
|
|
|
input_item_slave_New( uri, i_type, SLAVE_PRIORITY_USER );
|
2016-06-07 13:44:50 +02:00
|
|
|
free( uri );
|
2016-06-07 13:44:09 +02:00
|
|
|
|
|
|
|
if( unlikely( p_slave == NULL ) )
|
|
|
|
break;
|
2017-05-18 19:47:15 +02:00
|
|
|
TAB_APPEND(i_slaves, pp_slaves, p_slave);
|
2016-06-07 13:44:50 +02:00
|
|
|
}
|
|
|
|
free( psz_org );
|
2016-06-07 13:44:09 +02:00
|
|
|
|
|
|
|
*ppp_slaves = pp_slaves; /* in case of realloc */
|
|
|
|
*p_slaves = i_slaves;
|
2016-06-07 13:44:50 +02:00
|
|
|
}
|
|
|
|
|
2016-03-24 10:22:28 +01:00
|
|
|
static void LoadSlaves( input_thread_t *p_input )
|
2016-03-25 11:37:33 +01:00
|
|
|
{
|
2016-05-31 14:18:51 +02:00
|
|
|
input_item_slave_t **pp_slaves;
|
|
|
|
int i_slaves;
|
|
|
|
TAB_INIT( i_slaves, pp_slaves );
|
|
|
|
|
2016-03-24 10:22:28 +01:00
|
|
|
/* Look for and add slaves */
|
2010-01-12 23:16:55 +01:00
|
|
|
|
2008-12-01 23:52:02 +01:00
|
|
|
char *psz_subtitle = var_GetNonEmptyString( p_input, "sub-file" );
|
2008-04-14 12:32:44 +02:00
|
|
|
if( psz_subtitle != NULL )
|
|
|
|
{
|
|
|
|
msg_Dbg( p_input, "forced subtitle: %s", psz_subtitle );
|
2016-03-25 13:56:11 +01:00
|
|
|
char *psz_uri = input_SubtitleFile2Uri( p_input, psz_subtitle );
|
2016-05-30 18:02:02 +02:00
|
|
|
free( psz_subtitle );
|
|
|
|
psz_subtitle = NULL;
|
2016-03-25 13:56:11 +01:00
|
|
|
if( psz_uri != NULL )
|
|
|
|
{
|
2016-05-30 18:02:02 +02:00
|
|
|
input_item_slave_t *p_slave =
|
|
|
|
input_item_slave_New( psz_uri, SLAVE_TYPE_SPU,
|
|
|
|
SLAVE_PRIORITY_USER );
|
|
|
|
free( psz_uri );
|
|
|
|
if( p_slave )
|
|
|
|
{
|
2017-05-18 19:47:15 +02:00
|
|
|
TAB_APPEND(i_slaves, pp_slaves, p_slave);
|
2016-05-30 18:02:02 +02:00
|
|
|
psz_subtitle = p_slave->psz_uri;
|
|
|
|
}
|
2016-03-25 13:56:11 +01:00
|
|
|
}
|
2008-04-14 12:32:44 +02:00
|
|
|
}
|
|
|
|
|
2008-12-01 23:52:02 +01:00
|
|
|
if( var_GetBool( p_input, "sub-autodetect-file" ) )
|
2008-04-14 12:32:44 +02:00
|
|
|
{
|
2016-03-24 10:21:32 +01:00
|
|
|
/* Add local subtitles */
|
2008-04-14 12:32:44 +02:00
|
|
|
char *psz_autopath = var_GetNonEmptyString( p_input, "sub-autodetect-path" );
|
|
|
|
|
2016-11-05 09:11:44 +01:00
|
|
|
if( subtitles_Detect( p_input, psz_autopath, input_priv(p_input)->p_item->psz_uri,
|
2016-03-24 10:21:32 +01:00
|
|
|
&pp_slaves, &i_slaves ) == VLC_SUCCESS )
|
2004-06-25 20:35:56 +02:00
|
|
|
{
|
2016-03-24 10:21:32 +01:00
|
|
|
/* check that we did not add the subtitle through sub-file */
|
2016-06-27 15:38:55 +02:00
|
|
|
if( psz_subtitle != NULL )
|
2010-01-12 23:16:55 +01:00
|
|
|
{
|
2016-06-27 15:38:55 +02:00
|
|
|
for( int i = 1; i < i_slaves; i++ )
|
2016-03-24 10:21:32 +01:00
|
|
|
{
|
2016-06-27 15:38:55 +02:00
|
|
|
input_item_slave_t *p_curr = pp_slaves[i];
|
2016-07-30 09:41:28 +02:00
|
|
|
if( p_curr != NULL
|
2016-06-27 15:38:55 +02:00
|
|
|
&& !strcmp( psz_subtitle, p_curr->psz_uri ) )
|
|
|
|
{
|
|
|
|
/* reject current sub */
|
|
|
|
input_item_slave_Delete( p_curr );
|
|
|
|
pp_slaves[i] = NULL;
|
|
|
|
}
|
2016-03-24 10:21:32 +01:00
|
|
|
}
|
2010-01-12 23:16:55 +01:00
|
|
|
}
|
2016-03-24 10:21:32 +01:00
|
|
|
}
|
|
|
|
free( psz_autopath );
|
2016-05-31 14:18:51 +02:00
|
|
|
}
|
2008-09-18 20:15:29 +02:00
|
|
|
|
2021-04-22 11:42:12 +02:00
|
|
|
/* Add slaves from the "input-slave" option */
|
|
|
|
GetVarSlaves( p_input, &pp_slaves, &i_slaves );
|
|
|
|
|
2016-05-31 14:18:51 +02:00
|
|
|
/* Add slaves found by the directory demuxer or via libvlc */
|
2016-11-05 09:11:44 +01:00
|
|
|
input_item_t *p_item = input_priv(p_input)->p_item;
|
2016-05-31 14:18:51 +02:00
|
|
|
vlc_mutex_lock( &p_item->lock );
|
2016-05-30 18:22:41 +02:00
|
|
|
|
|
|
|
/* Move item slaves to local pp_slaves */
|
2016-05-31 14:18:51 +02:00
|
|
|
for( int i = 0; i < p_item->i_slaves; i++ )
|
|
|
|
{
|
|
|
|
input_item_slave_t *p_slave = p_item->pp_slaves[i];
|
2016-06-27 15:38:55 +02:00
|
|
|
if( !SlaveExists( pp_slaves, i_slaves, p_slave->psz_uri ) )
|
2017-05-18 19:47:15 +02:00
|
|
|
TAB_APPEND(i_slaves, pp_slaves, p_slave);
|
2016-05-30 18:22:41 +02:00
|
|
|
else
|
|
|
|
input_item_slave_Delete( p_slave );
|
2016-05-31 14:18:51 +02:00
|
|
|
}
|
2016-06-07 17:14:39 +02:00
|
|
|
/* Slaves that are successfully loaded will be added back to the item */
|
2016-05-30 18:22:41 +02:00
|
|
|
TAB_CLEAN( p_item->i_slaves, p_item->pp_slaves );
|
2016-06-07 17:14:39 +02:00
|
|
|
vlc_mutex_unlock( &p_item->lock );
|
2016-05-30 18:22:41 +02:00
|
|
|
|
2021-04-22 14:53:39 +02:00
|
|
|
if( i_slaves > 0 ) /* Sort by priority */
|
2016-05-31 14:18:51 +02:00
|
|
|
qsort( pp_slaves, i_slaves, sizeof (input_item_slave_t*),
|
|
|
|
SlaveCompare );
|
2016-03-24 10:21:32 +01:00
|
|
|
|
2016-05-31 14:18:51 +02:00
|
|
|
/* add all detected slaves */
|
2021-04-22 14:25:22 +02:00
|
|
|
static_assert( SLAVE_TYPE_GENERIC <= 1 && SLAVE_TYPE_SPU <= 1,
|
2016-06-07 17:19:45 +02:00
|
|
|
"slave type size mismatch");
|
2016-06-07 17:14:39 +02:00
|
|
|
for( int i = 0; i < i_slaves && pp_slaves[i] != NULL; i++ )
|
2016-05-31 14:18:51 +02:00
|
|
|
{
|
|
|
|
input_item_slave_t *p_slave = pp_slaves[i];
|
2016-06-07 17:19:19 +02:00
|
|
|
/* Slaves added via options should not fail */
|
|
|
|
unsigned i_flags = p_slave->i_priority != SLAVE_PRIORITY_USER
|
|
|
|
? SLAVE_ADD_CANFAIL : SLAVE_ADD_NOFLAG;
|
|
|
|
|
2017-10-30 15:55:06 +01:00
|
|
|
/* Force the first subtitle with the highest priority or with the
|
|
|
|
* forced flag */
|
2021-04-22 15:37:18 +02:00
|
|
|
if ( p_slave->b_forced || p_slave->i_priority >= SLAVE_PRIORITY_MATCH_ALL )
|
2016-06-07 17:19:19 +02:00
|
|
|
i_flags |= SLAVE_ADD_FORCED;
|
|
|
|
|
|
|
|
if( input_SlaveSourceAdd( p_input, p_slave->i_type, p_slave->psz_uri,
|
|
|
|
i_flags ) == VLC_SUCCESS )
|
2016-11-05 09:11:44 +01:00
|
|
|
input_item_AddSlave( input_priv(p_input)->p_item, p_slave );
|
2016-05-31 14:18:51 +02:00
|
|
|
else
|
2016-06-07 17:19:19 +02:00
|
|
|
input_item_slave_Delete( p_slave );
|
2008-04-14 12:32:44 +02:00
|
|
|
}
|
2016-06-07 17:14:39 +02:00
|
|
|
TAB_CLEAN( i_slaves, pp_slaves );
|
2016-05-31 14:18:51 +02:00
|
|
|
|
2010-01-12 23:16:55 +01:00
|
|
|
/* Load subtitles from attachments */
|
|
|
|
int i_attachment = 0;
|
2010-01-23 21:16:39 +01:00
|
|
|
input_attachment_t **pp_attachment = NULL;
|
2010-01-12 23:16:55 +01:00
|
|
|
|
2016-11-05 09:11:44 +01:00
|
|
|
vlc_mutex_lock( &input_priv(p_input)->p_item->lock );
|
|
|
|
for( int i = 0; i < input_priv(p_input)->i_attachment; i++ )
|
2010-01-12 23:16:55 +01:00
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
const input_attachment_t *a = input_priv(p_input)->attachment[i];
|
2010-01-12 23:16:55 +01:00
|
|
|
if( !strcmp( a->psz_mime, "application/x-srt" ) )
|
2010-01-23 21:16:39 +01:00
|
|
|
TAB_APPEND( i_attachment, pp_attachment,
|
|
|
|
vlc_input_attachment_New( a->psz_name, NULL,
|
|
|
|
a->psz_description, NULL, 0 ) );
|
2010-01-12 23:16:55 +01:00
|
|
|
}
|
2016-11-05 09:11:44 +01:00
|
|
|
vlc_mutex_unlock( &input_priv(p_input)->p_item->lock );
|
2010-01-12 23:16:55 +01:00
|
|
|
|
2010-01-23 21:16:39 +01:00
|
|
|
if( i_attachment > 0 )
|
|
|
|
var_Create( p_input, "sub-description", VLC_VAR_STRING );
|
2010-01-12 23:16:55 +01:00
|
|
|
for( int i = 0; i < i_attachment; i++ )
|
|
|
|
{
|
2010-01-23 21:16:39 +01:00
|
|
|
input_attachment_t *a = pp_attachment[i];
|
|
|
|
if( !a )
|
|
|
|
continue;
|
2010-01-12 23:16:55 +01:00
|
|
|
char *psz_mrl;
|
2015-08-15 12:19:39 +02:00
|
|
|
if( a->psz_name[0] &&
|
2010-01-23 21:16:39 +01:00
|
|
|
asprintf( &psz_mrl, "attachment://%s", a->psz_name ) >= 0 )
|
2010-01-12 23:16:55 +01:00
|
|
|
{
|
2010-01-23 21:16:39 +01:00
|
|
|
var_SetString( p_input, "sub-description", a->psz_description ? a->psz_description : "");
|
|
|
|
|
2017-10-30 15:55:06 +01:00
|
|
|
/* Force the first subtitle from attachment if there is no
|
|
|
|
* subtitles already forced */
|
2021-04-22 14:53:39 +02:00
|
|
|
input_SlaveSourceAdd( p_input, SLAVE_TYPE_SPU, psz_mrl,
|
|
|
|
SLAVE_ADD_FORCED );
|
2017-10-30 13:07:47 +01:00
|
|
|
|
2010-01-12 23:16:55 +01:00
|
|
|
free( psz_mrl );
|
2021-12-15 15:25:39 +01:00
|
|
|
/* Don't update item slaves for attachments */
|
2010-01-12 23:16:55 +01:00
|
|
|
}
|
2020-10-27 17:14:28 +01:00
|
|
|
vlc_input_attachment_Release( a );
|
2010-01-12 23:16:55 +01:00
|
|
|
}
|
2010-01-23 21:16:39 +01:00
|
|
|
free( pp_attachment );
|
|
|
|
if( i_attachment > 0 )
|
|
|
|
var_Destroy( p_input, "sub-description" );
|
2008-12-01 23:52:02 +01:00
|
|
|
}
|
2004-06-27 21:54:35 +02:00
|
|
|
|
2009-01-18 17:44:56 +01:00
|
|
|
static void UpdatePtsDelay( input_thread_t *p_input )
|
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
input_thread_private_t *p_sys = input_priv(p_input);
|
2009-01-18 17:44:56 +01:00
|
|
|
|
|
|
|
/* Get max pts delay from input source */
|
2018-06-22 13:19:24 +02:00
|
|
|
vlc_tick_t i_pts_delay = p_sys->master->i_pts_delay;
|
2009-01-18 17:44:56 +01:00
|
|
|
for( int i = 0; i < p_sys->i_slave; i++ )
|
|
|
|
i_pts_delay = __MAX( i_pts_delay, p_sys->slave[i]->i_pts_delay );
|
|
|
|
|
|
|
|
if( i_pts_delay < 0 )
|
|
|
|
i_pts_delay = 0;
|
|
|
|
|
|
|
|
/* Update cr_average depending on the caching */
|
|
|
|
const int i_cr_average = var_GetInteger( p_input, "cr-average" ) * i_pts_delay / DEFAULT_PTS_DELAY;
|
|
|
|
|
2016-11-05 09:11:44 +01:00
|
|
|
es_out_SetJitter( input_priv(p_input)->p_es_out, i_pts_delay, 0, i_cr_average );
|
2009-01-18 17:44:56 +01:00
|
|
|
}
|
|
|
|
|
2008-04-14 12:32:44 +02:00
|
|
|
static void InitPrograms( input_thread_t * p_input )
|
|
|
|
{
|
|
|
|
int i_es_out_mode;
|
2018-06-09 11:46:47 +02:00
|
|
|
int *tab;
|
|
|
|
size_t count;
|
2008-04-14 12:32:44 +02:00
|
|
|
|
2020-11-27 17:11:36 +01:00
|
|
|
TAB_INIT(count, tab);
|
|
|
|
|
2009-01-18 17:44:56 +01:00
|
|
|
/* Compute correct pts_delay */
|
|
|
|
UpdatePtsDelay( p_input );
|
|
|
|
|
2004-06-22 21:29:57 +02:00
|
|
|
/* Set up es_out */
|
2008-04-14 12:32:44 +02:00
|
|
|
i_es_out_mode = ES_OUT_MODE_AUTO;
|
2018-01-19 16:26:27 +01:00
|
|
|
if( input_priv(p_input)->p_sout && !input_priv(p_input)->p_renderer )
|
2004-06-22 21:29:57 +02:00
|
|
|
{
|
2010-06-08 19:39:01 +02:00
|
|
|
char *prgms;
|
|
|
|
|
|
|
|
if( (prgms = var_GetNonEmptyString( p_input, "programs" )) != NULL )
|
2008-04-14 12:32:44 +02:00
|
|
|
{
|
2010-06-08 19:39:01 +02:00
|
|
|
char *buf;
|
|
|
|
|
|
|
|
for( const char *prgm = strtok_r( prgms, ",", &buf );
|
|
|
|
prgm != NULL;
|
|
|
|
prgm = strtok_r( NULL, ",", &buf ) )
|
2004-10-22 15:49:14 +02:00
|
|
|
{
|
2018-06-09 11:46:47 +02:00
|
|
|
TAB_APPEND(count, tab, atoi(prgm));
|
2010-06-08 19:39:01 +02:00
|
|
|
}
|
|
|
|
|
2018-06-09 11:46:47 +02:00
|
|
|
if( count > 0 )
|
2008-04-14 12:32:44 +02:00
|
|
|
i_es_out_mode = ES_OUT_MODE_PARTIAL;
|
|
|
|
/* Note : we should remove the "program" callback. */
|
2010-06-08 19:39:01 +02:00
|
|
|
|
|
|
|
free( prgms );
|
2004-10-22 15:49:14 +02:00
|
|
|
}
|
2014-08-21 15:21:59 +02:00
|
|
|
else if( var_GetBool( p_input, "sout-all" ) )
|
|
|
|
{
|
|
|
|
i_es_out_mode = ES_OUT_MODE_ALL;
|
|
|
|
}
|
2008-04-14 12:32:44 +02:00
|
|
|
}
|
2016-11-05 09:11:44 +01:00
|
|
|
es_out_SetMode( input_priv(p_input)->p_es_out, i_es_out_mode );
|
2004-08-25 22:08:23 +02:00
|
|
|
|
2008-04-14 12:32:44 +02:00
|
|
|
/* Inform the demuxer about waited group (needed only for DVB) */
|
|
|
|
if( i_es_out_mode == ES_OUT_MODE_ALL )
|
|
|
|
{
|
2018-06-09 10:51:59 +02:00
|
|
|
demux_Control( input_priv(p_input)->master->p_demux,
|
|
|
|
DEMUX_SET_GROUP_ALL );
|
2008-04-14 12:32:44 +02:00
|
|
|
}
|
|
|
|
else if( i_es_out_mode == ES_OUT_MODE_PARTIAL )
|
|
|
|
{
|
2018-06-09 10:51:59 +02:00
|
|
|
demux_Control( input_priv(p_input)->master->p_demux,
|
2018-06-09 11:46:47 +02:00
|
|
|
DEMUX_SET_GROUP_LIST, count, tab );
|
|
|
|
free(tab);
|
2008-04-14 12:32:44 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-06-09 11:04:12 +02:00
|
|
|
int program = es_out_GetGroupForced( input_priv(p_input)->p_es_out );
|
|
|
|
if( program == 0 )
|
|
|
|
demux_Control( input_priv(p_input)->master->p_demux,
|
2018-06-09 11:31:44 +02:00
|
|
|
DEMUX_SET_GROUP_DEFAULT );
|
2018-06-09 11:04:12 +02:00
|
|
|
else
|
|
|
|
demux_Control( input_priv(p_input)->master->p_demux,
|
2018-06-09 11:46:47 +02:00
|
|
|
DEMUX_SET_GROUP_LIST, (size_t)1,
|
|
|
|
(const int *)&program );
|
2008-04-14 12:32:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int Init( input_thread_t * p_input )
|
|
|
|
{
|
2016-11-05 10:22:30 +01:00
|
|
|
input_thread_private_t *priv = input_priv(p_input);
|
2015-10-24 19:57:33 +02:00
|
|
|
input_source_t *master;
|
|
|
|
|
2018-11-13 16:32:02 +01:00
|
|
|
/* */
|
2019-08-13 17:57:39 +02:00
|
|
|
input_ChangeState( p_input, OPENING_S, VLC_TICK_INVALID );
|
2018-11-13 16:32:02 +01:00
|
|
|
input_SendEventCache( p_input, 0.0 );
|
|
|
|
|
2019-02-27 18:27:01 +01:00
|
|
|
if( var_Type( vlc_object_parent(p_input), "meta-file" ) )
|
2008-04-14 12:32:44 +02:00
|
|
|
{
|
2016-04-13 22:16:13 +02:00
|
|
|
msg_Dbg( p_input, "Input is a meta file: disabling unneeded options" );
|
|
|
|
var_SetString( p_input, "sout", "" );
|
|
|
|
var_SetBool( p_input, "sout-all", false );
|
|
|
|
var_SetString( p_input, "input-slave", "" );
|
|
|
|
var_SetInteger( p_input, "input-repeat", 0 );
|
|
|
|
var_SetString( p_input, "sub-file", "" );
|
|
|
|
var_SetBool( p_input, "sub-autodetect-file", false );
|
2008-04-14 12:32:44 +02:00
|
|
|
}
|
|
|
|
|
2008-05-01 19:04:27 +02:00
|
|
|
#ifdef ENABLE_SOUT
|
2010-01-31 01:04:48 +01:00
|
|
|
if( InitSout( p_input ) )
|
2010-01-31 01:13:05 +01:00
|
|
|
goto error;
|
2008-05-01 19:04:27 +02:00
|
|
|
#endif
|
2008-04-14 12:32:44 +02:00
|
|
|
|
|
|
|
/* Create es out */
|
2019-02-15 15:38:39 +01:00
|
|
|
priv->p_es_out = input_EsOutTimeshiftNew( p_input, priv->p_es_out_display, priv->rate );
|
2017-01-09 15:59:28 +01:00
|
|
|
if( priv->p_es_out == NULL )
|
|
|
|
goto error;
|
2008-04-14 12:32:44 +02:00
|
|
|
|
2008-12-04 22:43:46 +01:00
|
|
|
/* */
|
2020-02-27 18:17:19 +01:00
|
|
|
master = priv->master;
|
2015-10-24 19:57:33 +02:00
|
|
|
if( master == NULL )
|
2008-04-14 12:32:44 +02:00
|
|
|
goto error;
|
2020-02-26 14:43:13 +01:00
|
|
|
int ret = InputSourceInit( master, p_input, priv->p_item->psz_uri,
|
|
|
|
NULL, false );
|
|
|
|
if( ret != VLC_SUCCESS )
|
|
|
|
{
|
|
|
|
InputSourceDestroy( master );
|
|
|
|
goto error;
|
|
|
|
}
|
2008-04-14 12:32:44 +02:00
|
|
|
|
2021-04-27 13:46:29 +02:00
|
|
|
InitProperties( p_input );
|
|
|
|
|
2018-09-11 17:50:09 +02:00
|
|
|
InitTitle( p_input, false );
|
2008-04-14 12:32:44 +02:00
|
|
|
|
|
|
|
/* Load master infos */
|
|
|
|
/* Init length */
|
2018-06-22 13:19:24 +02:00
|
|
|
vlc_tick_t i_length;
|
2015-10-24 19:57:33 +02:00
|
|
|
if( demux_Control( master->p_demux, DEMUX_GET_LENGTH, &i_length ) )
|
2020-12-03 16:07:46 +01:00
|
|
|
i_length = 0;
|
|
|
|
if( i_length == 0 )
|
2016-11-05 10:22:30 +01:00
|
|
|
i_length = input_item_GetDuration( priv->p_item );
|
2009-05-11 22:17:54 +02:00
|
|
|
|
2019-09-10 18:28:04 +02:00
|
|
|
input_SendEventTimes( p_input, 0.0, VLC_TICK_INVALID, priv->normal_time,
|
|
|
|
i_length );
|
2004-12-10 19:58:22 +01:00
|
|
|
|
2019-06-26 13:35:06 +02:00
|
|
|
if( priv->type != INPUT_TYPE_PREPARSING )
|
2008-12-01 23:52:02 +01:00
|
|
|
{
|
2008-12-02 00:03:33 +01:00
|
|
|
StartTitle( p_input );
|
2016-03-25 11:37:33 +01:00
|
|
|
SetSubtitlesOptions( p_input );
|
2008-12-01 23:52:02 +01:00
|
|
|
LoadSlaves( p_input );
|
|
|
|
InitPrograms( p_input );
|
2011-06-25 23:29:55 +02:00
|
|
|
|
2018-07-18 16:36:17 +02:00
|
|
|
double f_rate = var_GetFloat( p_input, "rate" );
|
2011-06-25 23:29:55 +02:00
|
|
|
if( f_rate != 0.0 && f_rate != 1.0 )
|
|
|
|
{
|
2019-02-15 15:38:39 +01:00
|
|
|
vlc_value_t val = { .f_float = f_rate };
|
2018-06-25 10:03:48 +02:00
|
|
|
input_ControlPushHelper( p_input, INPUT_CONTROL_SET_RATE, &val );
|
2011-06-25 23:29:55 +02:00
|
|
|
}
|
2008-12-01 23:52:02 +01:00
|
|
|
}
|
2008-04-14 12:32:44 +02:00
|
|
|
|
2020-11-24 10:22:38 +01:00
|
|
|
#ifdef ENABLE_SOUT
|
2019-06-26 13:35:06 +02:00
|
|
|
if( priv->type != INPUT_TYPE_PREPARSING && priv->p_sout )
|
2008-04-14 12:32:44 +02:00
|
|
|
{
|
2021-07-13 18:04:21 +02:00
|
|
|
priv->b_out_pace_control = sout_StreamIsSynchronous(priv->p_sout);
|
2016-11-05 10:22:30 +01:00
|
|
|
msg_Dbg( p_input, "starting in %ssync mode",
|
|
|
|
priv->b_out_pace_control ? "a" : "" );
|
2002-08-13 00:12:51 +02:00
|
|
|
}
|
2020-11-24 10:22:38 +01:00
|
|
|
#endif
|
2002-08-13 00:12:51 +02:00
|
|
|
|
2019-02-07 16:00:52 +01:00
|
|
|
if (!input_item_IsPreparsed(input_priv(p_input)->p_item))
|
|
|
|
{
|
2019-02-07 16:01:28 +01:00
|
|
|
vlc_meta_t *p_meta = vlc_meta_New();
|
|
|
|
if( p_meta != NULL )
|
|
|
|
{
|
|
|
|
/* Get meta data from users */
|
|
|
|
InputMetaUser( p_input, p_meta );
|
2008-04-14 12:32:44 +02:00
|
|
|
|
2019-02-07 16:01:28 +01:00
|
|
|
/* Get meta data from master input */
|
|
|
|
InputSourceMeta( p_input, master, p_meta );
|
2004-11-15 18:07:06 +01:00
|
|
|
|
2019-02-07 16:01:28 +01:00
|
|
|
/* And from slave */
|
|
|
|
for( int i = 0; i < priv->i_slave; i++ )
|
|
|
|
InputSourceMeta( p_input, priv->slave[i], p_meta );
|
2004-01-31 06:25:36 +01:00
|
|
|
|
2019-02-07 16:01:28 +01:00
|
|
|
es_out_ControlSetMeta( priv->p_es_out, p_meta );
|
|
|
|
vlc_meta_Delete( p_meta );
|
|
|
|
}
|
2019-02-07 16:00:52 +01:00
|
|
|
}
|
2008-04-17 01:15:57 +02:00
|
|
|
|
2009-02-11 21:38:54 +01:00
|
|
|
msg_Dbg( p_input, "`%s' successfully opened",
|
2016-11-05 09:11:44 +01:00
|
|
|
input_priv(p_input)->p_item->psz_uri );
|
2004-03-06 00:26:36 +01:00
|
|
|
|
2004-06-29 00:49:43 +02:00
|
|
|
/* initialization is complete */
|
2019-08-13 17:57:39 +02:00
|
|
|
input_ChangeState( p_input, PLAYING_S, vlc_tick_now() );
|
2004-03-11 13:33:16 +01:00
|
|
|
|
2004-06-29 00:49:43 +02:00
|
|
|
return VLC_SUCCESS;
|
2003-09-13 19:42:16 +02:00
|
|
|
|
2004-06-29 00:49:43 +02:00
|
|
|
error:
|
2019-08-13 17:57:39 +02:00
|
|
|
input_ChangeState( p_input, ERROR_S, VLC_TICK_INVALID );
|
2006-10-29 14:37:30 +01:00
|
|
|
|
2016-11-05 09:11:44 +01:00
|
|
|
if( input_priv(p_input)->p_es_out )
|
|
|
|
es_out_Delete( input_priv(p_input)->p_es_out );
|
|
|
|
es_out_SetMode( input_priv(p_input)->p_es_out_display, ES_OUT_MODE_END );
|
|
|
|
if( input_priv(p_input)->p_resource )
|
2007-03-07 23:38:34 +01:00
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
if( input_priv(p_input)->p_sout )
|
2021-01-19 18:56:51 +01:00
|
|
|
input_resource_PutSout( input_priv(p_input)->p_resource,
|
|
|
|
input_priv(p_input)->p_sout );
|
2016-11-05 09:11:44 +01:00
|
|
|
input_resource_SetInput( input_priv(p_input)->p_resource, NULL );
|
2019-06-27 10:00:32 +02:00
|
|
|
if( input_priv(p_input)->p_resource )
|
|
|
|
{
|
|
|
|
input_resource_Release( input_priv(p_input)->p_resource );
|
|
|
|
input_priv(p_input)->p_resource = NULL;
|
|
|
|
}
|
2007-03-07 23:38:34 +01:00
|
|
|
}
|
2007-03-24 02:05:02 +01:00
|
|
|
|
2004-06-29 00:49:43 +02:00
|
|
|
/* Mark them deleted */
|
2016-11-05 09:11:44 +01:00
|
|
|
input_priv(p_input)->p_es_out = NULL;
|
|
|
|
input_priv(p_input)->p_sout = NULL;
|
2003-09-13 19:42:16 +02:00
|
|
|
|
2004-06-29 00:49:43 +02:00
|
|
|
return VLC_EGENERIC;
|
1999-08-08 14:42:54 +02:00
|
|
|
}
|
|
|
|
|
2000-03-20 05:29:00 +01:00
|
|
|
/*****************************************************************************
|
2004-06-22 21:29:57 +02:00
|
|
|
* End: end the input thread
|
2000-03-20 05:29:00 +01:00
|
|
|
*****************************************************************************/
|
2004-06-22 21:29:57 +02:00
|
|
|
static void End( input_thread_t * p_input )
|
2000-03-20 05:29:00 +01:00
|
|
|
{
|
2016-11-05 10:22:30 +01:00
|
|
|
input_thread_private_t *priv = input_priv(p_input);
|
|
|
|
|
2004-06-22 21:29:57 +02:00
|
|
|
/* We are at the end */
|
2019-08-13 17:57:39 +02:00
|
|
|
input_ChangeState( p_input, END_S, VLC_TICK_INVALID );
|
2004-06-22 21:29:57 +02:00
|
|
|
|
2008-11-29 14:03:27 +01:00
|
|
|
/* Stop es out activity */
|
2016-11-05 10:22:30 +01:00
|
|
|
es_out_SetMode( priv->p_es_out, ES_OUT_MODE_NONE );
|
2008-11-29 14:03:27 +01:00
|
|
|
|
2004-06-25 00:21:36 +02:00
|
|
|
/* Delete slave */
|
2016-11-05 10:22:30 +01:00
|
|
|
for( int i = 0; i < priv->i_slave; i++ )
|
2020-02-27 18:16:44 +01:00
|
|
|
{
|
2016-11-05 10:22:30 +01:00
|
|
|
InputSourceDestroy( priv->slave[i] );
|
2020-02-27 18:16:44 +01:00
|
|
|
input_source_Release( priv->slave[i] );
|
|
|
|
}
|
2016-11-05 10:22:30 +01:00
|
|
|
free( priv->slave );
|
2004-06-22 21:29:57 +02:00
|
|
|
|
2015-10-24 19:57:33 +02:00
|
|
|
/* Clean up master */
|
2016-11-05 10:22:30 +01:00
|
|
|
InputSourceDestroy( priv->master );
|
2017-01-27 18:13:26 +01:00
|
|
|
priv->i_title_offset = 0;
|
|
|
|
priv->i_seekpoint_offset = 0;
|
2015-10-24 19:57:33 +02:00
|
|
|
|
2004-06-25 00:21:36 +02:00
|
|
|
/* Unload all modules */
|
2016-11-05 10:22:30 +01:00
|
|
|
if( priv->p_es_out )
|
|
|
|
es_out_Delete( priv->p_es_out );
|
|
|
|
es_out_SetMode( priv->p_es_out_display, ES_OUT_MODE_END );
|
2003-11-22 14:19:30 +01:00
|
|
|
|
2017-12-12 17:26:42 +01:00
|
|
|
if( priv->stats != NULL )
|
2006-08-06 14:25:52 +02:00
|
|
|
{
|
2017-12-12 17:26:42 +01:00
|
|
|
input_item_t *item = priv->p_item;
|
|
|
|
/* make sure we are up to date */
|
|
|
|
vlc_mutex_lock( &item->lock );
|
|
|
|
input_stats_Compute( priv->stats, item->p_stats );
|
|
|
|
vlc_mutex_unlock( &item->lock );
|
2007-02-28 23:45:02 +01:00
|
|
|
}
|
|
|
|
|
2016-11-05 10:22:30 +01:00
|
|
|
vlc_mutex_lock( &priv->p_item->lock );
|
|
|
|
if( priv->i_attachment > 0 )
|
2007-05-31 21:22:27 +02:00
|
|
|
{
|
2016-11-05 10:22:30 +01:00
|
|
|
for( int i = 0; i < priv->i_attachment; i++ )
|
2020-10-27 17:14:28 +01:00
|
|
|
vlc_input_attachment_Release( priv->attachment[i] );
|
2016-11-05 10:22:30 +01:00
|
|
|
TAB_CLEAN( priv->i_attachment, priv->attachment );
|
2007-05-31 21:22:27 +02:00
|
|
|
}
|
2017-05-18 14:46:07 +02:00
|
|
|
|
2016-11-05 09:11:44 +01:00
|
|
|
vlc_mutex_unlock( &input_priv(p_input)->p_item->lock );
|
2007-05-31 21:22:27 +02:00
|
|
|
|
2008-12-23 19:45:59 +01:00
|
|
|
/* */
|
2021-01-19 18:56:51 +01:00
|
|
|
input_resource_PutSout( input_priv(p_input)->p_resource,
|
|
|
|
input_priv(p_input)->p_sout );
|
2016-11-05 09:11:44 +01:00
|
|
|
input_resource_SetInput( input_priv(p_input)->p_resource, NULL );
|
2019-06-27 10:00:32 +02:00
|
|
|
if( input_priv(p_input)->p_resource )
|
|
|
|
{
|
|
|
|
input_resource_Release( input_priv(p_input)->p_resource );
|
|
|
|
input_priv(p_input)->p_resource = NULL;
|
|
|
|
}
|
2007-02-28 23:45:02 +01:00
|
|
|
}
|
2007-02-26 20:27:35 +01:00
|
|
|
|
2019-10-15 17:25:35 +02:00
|
|
|
static size_t ControlGetReducedIndexLocked( input_thread_t *p_input,
|
|
|
|
input_control_t *c )
|
|
|
|
{
|
|
|
|
input_thread_private_t *sys = input_priv(p_input);
|
|
|
|
|
|
|
|
if( sys->i_control == 0 )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
input_control_t *prev_control = &sys->control[sys->i_control - 1];
|
|
|
|
const int i_lt = prev_control->i_type;
|
|
|
|
const int i_ct = c->i_type;
|
|
|
|
|
|
|
|
if( i_lt == i_ct )
|
|
|
|
{
|
|
|
|
if ( i_ct == INPUT_CONTROL_SET_STATE ||
|
|
|
|
i_ct == INPUT_CONTROL_SET_RATE ||
|
|
|
|
i_ct == INPUT_CONTROL_SET_POSITION ||
|
|
|
|
i_ct == INPUT_CONTROL_SET_TIME ||
|
|
|
|
i_ct == INPUT_CONTROL_SET_PROGRAM ||
|
|
|
|
i_ct == INPUT_CONTROL_SET_TITLE ||
|
2022-05-26 02:18:53 +02:00
|
|
|
i_ct == INPUT_CONTROL_SET_SEEKPOINT ||
|
|
|
|
i_ct == INPUT_CONTROL_SET_VIEWPOINT )
|
2019-10-15 17:25:35 +02:00
|
|
|
{
|
|
|
|
return sys->i_control - 1;
|
|
|
|
}
|
2019-10-16 11:31:38 +02:00
|
|
|
else if ( i_ct == INPUT_CONTROL_JUMP_TIME )
|
|
|
|
{
|
|
|
|
c->param.time.i_val += prev_control->param.time.i_val;
|
|
|
|
return sys->i_control - 1;
|
|
|
|
}
|
|
|
|
else if ( i_ct == INPUT_CONTROL_JUMP_POSITION )
|
|
|
|
{
|
|
|
|
c->param.pos.f_val += prev_control->param.pos.f_val;
|
|
|
|
return sys->i_control - 1;
|
|
|
|
}
|
2022-05-26 02:18:53 +02:00
|
|
|
else if ( i_ct == INPUT_CONTROL_UPDATE_VIEWPOINT )
|
|
|
|
{
|
|
|
|
c->param.viewpoint.yaw += prev_control->param.viewpoint.yaw;
|
|
|
|
c->param.viewpoint.pitch += prev_control->param.viewpoint.pitch;
|
|
|
|
c->param.viewpoint.roll += prev_control->param.viewpoint.roll;
|
|
|
|
c->param.viewpoint.fov += prev_control->param.viewpoint.fov;
|
|
|
|
return sys->i_control - 1;
|
|
|
|
}
|
2019-10-15 17:25:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return sys->i_control;
|
|
|
|
}
|
|
|
|
|
2004-06-22 21:29:57 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* Control
|
|
|
|
*****************************************************************************/
|
2019-08-09 16:33:55 +02:00
|
|
|
int input_ControlPush( input_thread_t *p_input,
|
|
|
|
int i_type, const input_control_param_t *p_param )
|
2008-11-22 12:03:18 +01:00
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
input_thread_private_t *sys = input_priv(p_input);
|
2009-03-23 20:54:52 +01:00
|
|
|
|
2015-06-07 21:01:07 +02:00
|
|
|
vlc_mutex_lock( &sys->lock_control );
|
2019-10-15 17:25:35 +02:00
|
|
|
input_control_t c = {
|
|
|
|
.i_type = i_type,
|
|
|
|
};
|
|
|
|
if( p_param )
|
|
|
|
c.param = *p_param;
|
|
|
|
|
|
|
|
size_t i_next_control_idx = ControlGetReducedIndexLocked( p_input, &c );
|
|
|
|
|
|
|
|
if( sys->is_stopped || i_next_control_idx >= INPUT_CONTROL_FIFO_SIZE )
|
2008-11-22 12:03:18 +01:00
|
|
|
{
|
2016-05-31 12:11:56 +02:00
|
|
|
if( sys->is_stopped )
|
|
|
|
msg_Dbg( p_input, "input control stopped, trashing type=%d",
|
|
|
|
i_type );
|
|
|
|
else
|
|
|
|
msg_Err( p_input, "input control fifo overflow, trashing type=%d",
|
|
|
|
i_type );
|
2018-06-25 10:03:48 +02:00
|
|
|
if( p_param )
|
|
|
|
ControlRelease( i_type, p_param );
|
2019-08-09 16:33:55 +02:00
|
|
|
vlc_mutex_unlock( &sys->lock_control );
|
|
|
|
return VLC_EGENERIC;
|
2008-11-22 12:03:18 +01:00
|
|
|
}
|
2016-05-31 12:11:56 +02:00
|
|
|
|
2019-10-15 17:25:35 +02:00
|
|
|
sys->control[i_next_control_idx] = c;
|
|
|
|
sys->i_control = i_next_control_idx + 1;
|
2008-11-22 12:03:18 +01:00
|
|
|
|
2019-10-15 17:25:35 +02:00
|
|
|
vlc_cond_signal( &sys->wait_control );
|
|
|
|
vlc_mutex_unlock( &sys->lock_control );
|
|
|
|
return VLC_SUCCESS;
|
2009-11-27 23:21:38 +01:00
|
|
|
}
|
|
|
|
|
2009-01-24 11:11:42 +01:00
|
|
|
static inline int ControlPop( input_thread_t *p_input,
|
2018-06-25 10:03:48 +02:00
|
|
|
int *pi_type, input_control_param_t *p_param,
|
2018-06-22 13:19:24 +02:00
|
|
|
vlc_tick_t i_deadline, bool b_postpone_seek )
|
2004-06-22 21:29:57 +02:00
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
input_thread_private_t *p_sys = input_priv(p_input);
|
2008-09-07 22:19:33 +02:00
|
|
|
|
2009-01-24 11:11:42 +01:00
|
|
|
vlc_mutex_lock( &p_sys->lock_control );
|
2009-11-28 11:43:24 +01:00
|
|
|
while( p_sys->i_control <= 0 ||
|
|
|
|
( b_postpone_seek && ControlIsSeekRequest( p_sys->control[0].i_type ) ) )
|
2004-06-22 21:29:57 +02:00
|
|
|
{
|
2015-06-07 21:01:07 +02:00
|
|
|
if( p_sys->is_stopped )
|
2009-01-24 11:11:42 +01:00
|
|
|
{
|
|
|
|
vlc_mutex_unlock( &p_sys->lock_control );
|
2008-09-07 22:19:33 +02:00
|
|
|
return VLC_EGENERIC;
|
2009-01-24 11:11:42 +01:00
|
|
|
}
|
2008-09-07 22:19:33 +02:00
|
|
|
|
2015-02-21 15:57:32 +01:00
|
|
|
if( i_deadline >= 0 )
|
2009-01-24 11:11:42 +01:00
|
|
|
{
|
2015-02-21 15:57:32 +01:00
|
|
|
if( vlc_cond_timedwait( &p_sys->wait_control, &p_sys->lock_control,
|
|
|
|
i_deadline ) )
|
|
|
|
{
|
|
|
|
vlc_mutex_unlock( &p_sys->lock_control );
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
}
|
2009-01-24 11:11:42 +01:00
|
|
|
}
|
2015-02-21 15:57:32 +01:00
|
|
|
else
|
|
|
|
vlc_cond_wait( &p_sys->wait_control, &p_sys->lock_control );
|
2004-06-22 21:29:57 +02:00
|
|
|
}
|
2003-09-12 20:34:45 +02:00
|
|
|
|
2009-01-24 11:11:42 +01:00
|
|
|
/* */
|
2019-10-15 17:25:35 +02:00
|
|
|
*pi_type = p_sys->control[0].i_type;
|
|
|
|
*p_param = p_sys->control[0].param;
|
2002-03-01 01:33:18 +01:00
|
|
|
|
2019-10-15 17:25:35 +02:00
|
|
|
p_sys->i_control --;
|
2009-01-24 11:11:42 +01:00
|
|
|
if( p_sys->i_control > 0 )
|
2019-10-15 17:25:35 +02:00
|
|
|
memmove( &p_sys->control[0], &p_sys->control[1],
|
2009-01-24 11:11:42 +01:00
|
|
|
sizeof(*p_sys->control) * p_sys->i_control );
|
|
|
|
vlc_mutex_unlock( &p_sys->lock_control );
|
2003-06-28 19:20:41 +02:00
|
|
|
|
2004-06-22 21:29:57 +02:00
|
|
|
return VLC_SUCCESS;
|
|
|
|
}
|
2009-11-28 11:43:24 +01:00
|
|
|
static bool ControlIsSeekRequest( int i_type )
|
|
|
|
{
|
|
|
|
switch( i_type )
|
|
|
|
{
|
|
|
|
case INPUT_CONTROL_SET_POSITION:
|
2018-10-10 13:20:02 +02:00
|
|
|
case INPUT_CONTROL_JUMP_POSITION:
|
2009-11-28 11:43:24 +01:00
|
|
|
case INPUT_CONTROL_SET_TIME:
|
2018-10-10 13:20:02 +02:00
|
|
|
case INPUT_CONTROL_JUMP_TIME:
|
2009-11-28 11:43:24 +01:00
|
|
|
case INPUT_CONTROL_SET_TITLE:
|
|
|
|
case INPUT_CONTROL_SET_TITLE_NEXT:
|
|
|
|
case INPUT_CONTROL_SET_TITLE_PREV:
|
|
|
|
case INPUT_CONTROL_SET_SEEKPOINT:
|
|
|
|
case INPUT_CONTROL_SET_SEEKPOINT_NEXT:
|
|
|
|
case INPUT_CONTROL_SET_SEEKPOINT_PREV:
|
2013-02-01 16:54:34 +01:00
|
|
|
case INPUT_CONTROL_NAV_ACTIVATE:
|
|
|
|
case INPUT_CONTROL_NAV_UP:
|
|
|
|
case INPUT_CONTROL_NAV_DOWN:
|
|
|
|
case INPUT_CONTROL_NAV_LEFT:
|
|
|
|
case INPUT_CONTROL_NAV_RIGHT:
|
2015-11-20 11:29:59 +01:00
|
|
|
case INPUT_CONTROL_NAV_POPUP:
|
2016-05-13 10:51:23 +02:00
|
|
|
case INPUT_CONTROL_NAV_MENU:
|
2009-11-28 11:43:24 +01:00
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2002-07-25 01:11:55 +02:00
|
|
|
|
2018-09-04 10:10:52 +02:00
|
|
|
static void ControlRelease( int i_type, const input_control_param_t *p_param )
|
2009-03-23 20:44:11 +01:00
|
|
|
{
|
2018-06-25 10:03:48 +02:00
|
|
|
if( p_param == NULL )
|
|
|
|
return;
|
|
|
|
|
2009-03-23 20:44:11 +01:00
|
|
|
switch( i_type )
|
|
|
|
{
|
2016-05-27 11:41:06 +02:00
|
|
|
case INPUT_CONTROL_ADD_SLAVE:
|
2018-06-25 10:03:48 +02:00
|
|
|
if( p_param->val.p_address )
|
|
|
|
input_item_slave_Delete( p_param->val.p_address );
|
2016-11-10 18:24:18 +01:00
|
|
|
break;
|
2017-12-01 11:25:57 +01:00
|
|
|
case INPUT_CONTROL_SET_RENDERER:
|
2018-06-25 10:03:48 +02:00
|
|
|
if( p_param->val.p_address )
|
|
|
|
vlc_renderer_item_release( p_param->val.p_address );
|
2017-12-01 11:25:57 +01:00
|
|
|
break;
|
2018-08-29 12:01:57 +02:00
|
|
|
case INPUT_CONTROL_SET_ES:
|
|
|
|
case INPUT_CONTROL_UNSET_ES:
|
|
|
|
case INPUT_CONTROL_RESTART_ES:
|
|
|
|
vlc_es_id_Release( p_param->id );
|
|
|
|
break;
|
2019-06-20 13:29:58 +02:00
|
|
|
case INPUT_CONTROL_SET_ES_LIST:
|
|
|
|
{
|
|
|
|
for (size_t i = 0; ; i++)
|
|
|
|
{
|
|
|
|
vlc_es_id_t *es_id = p_param->list.ids[i];
|
|
|
|
if (es_id == NULL)
|
|
|
|
break;
|
|
|
|
vlc_es_id_Release(es_id);
|
|
|
|
}
|
|
|
|
free(p_param->list.ids);
|
|
|
|
break;
|
|
|
|
}
|
2020-02-20 15:33:54 +01:00
|
|
|
case INPUT_CONTROL_SET_ES_CAT_IDS:
|
|
|
|
free( p_param->cat_ids.str_ids );
|
|
|
|
break;
|
2022-08-10 15:43:58 +02:00
|
|
|
case INPUT_CONTROL_SET_RECORD_STATE:
|
|
|
|
free( p_param->record_state.dir_path );
|
|
|
|
break;
|
2009-03-23 20:44:11 +01:00
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-13 23:13:29 +02:00
|
|
|
/* Pause input */
|
2018-06-22 13:19:24 +02:00
|
|
|
static void ControlPause( input_thread_t *p_input, vlc_tick_t i_control_date )
|
2008-10-13 23:13:29 +02:00
|
|
|
{
|
2008-11-13 00:10:01 +01:00
|
|
|
int i_state = PAUSE_S;
|
2008-10-13 23:13:29 +02:00
|
|
|
|
2021-04-27 13:33:21 +02:00
|
|
|
if( input_priv(p_input)->master->b_can_pause )
|
2008-10-13 23:13:29 +02:00
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
demux_t *p_demux = input_priv(p_input)->master->p_demux;
|
2013-08-27 21:40:06 +02:00
|
|
|
|
2015-10-20 22:29:33 +02:00
|
|
|
if( demux_Control( p_demux, DEMUX_SET_PAUSE_STATE, true ) )
|
2008-11-13 00:10:01 +01:00
|
|
|
{
|
|
|
|
msg_Warn( p_input, "cannot set pause state" );
|
2009-08-23 17:17:05 +02:00
|
|
|
return;
|
2008-11-13 00:10:01 +01:00
|
|
|
}
|
2008-10-13 23:13:29 +02:00
|
|
|
}
|
|
|
|
|
2008-11-15 20:28:08 +01:00
|
|
|
/* */
|
2021-04-27 13:33:21 +02:00
|
|
|
if( es_out_SetPauseState( input_priv(p_input)->p_es_out,
|
|
|
|
input_priv(p_input)->master->b_can_pause,
|
2015-10-20 22:29:33 +02:00
|
|
|
true, i_control_date ) )
|
2008-11-15 20:28:08 +01:00
|
|
|
{
|
2009-08-23 17:17:05 +02:00
|
|
|
msg_Warn( p_input, "cannot set pause state at es_out level" );
|
|
|
|
return;
|
2008-11-15 20:28:08 +01:00
|
|
|
}
|
|
|
|
|
2008-10-13 23:13:29 +02:00
|
|
|
/* Switch to new state */
|
2019-08-13 17:57:39 +02:00
|
|
|
input_ChangeState( p_input, i_state, i_control_date );
|
2008-10-13 23:13:29 +02:00
|
|
|
}
|
2008-11-19 16:07:34 +01:00
|
|
|
|
2018-06-22 13:19:24 +02:00
|
|
|
static void ControlUnpause( input_thread_t *p_input, vlc_tick_t i_control_date )
|
2008-10-13 23:13:29 +02:00
|
|
|
{
|
2021-04-27 13:33:21 +02:00
|
|
|
if( input_priv(p_input)->master->b_can_pause )
|
2008-10-13 23:13:29 +02:00
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
demux_t *p_demux = input_priv(p_input)->master->p_demux;
|
2013-08-27 21:40:06 +02:00
|
|
|
|
2015-10-20 22:29:33 +02:00
|
|
|
if( demux_Control( p_demux, DEMUX_SET_PAUSE_STATE, false ) )
|
2008-11-13 00:10:01 +01:00
|
|
|
{
|
2015-06-06 20:32:41 +02:00
|
|
|
msg_Err( p_input, "cannot resume" );
|
2019-08-13 17:57:39 +02:00
|
|
|
input_ChangeState( p_input, ERROR_S, i_control_date );
|
2015-06-06 20:32:41 +02:00
|
|
|
return;
|
2008-11-13 00:10:01 +01:00
|
|
|
}
|
2008-10-13 23:13:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Switch to play */
|
2019-08-13 17:57:39 +02:00
|
|
|
input_ChangeState( p_input, PLAYING_S, i_control_date );
|
2016-11-05 09:11:44 +01:00
|
|
|
es_out_SetPauseState( input_priv(p_input)->p_es_out, false, false, i_control_date );
|
2008-10-13 23:13:29 +02:00
|
|
|
}
|
2004-06-22 21:29:57 +02:00
|
|
|
|
2017-09-04 11:52:05 +02:00
|
|
|
static void ViewpointApply( input_thread_t *p_input )
|
|
|
|
{
|
|
|
|
input_thread_private_t *priv = input_priv(p_input);
|
|
|
|
|
|
|
|
vlc_viewpoint_clip( &priv->viewpoint );
|
|
|
|
|
|
|
|
vout_thread_t **pp_vout;
|
|
|
|
size_t i_vout;
|
|
|
|
input_resource_HoldVouts( priv->p_resource, &pp_vout, &i_vout );
|
|
|
|
|
|
|
|
for( size_t i = 0; i < i_vout; ++i )
|
|
|
|
{
|
|
|
|
var_SetAddress( pp_vout[i], "viewpoint", &priv->viewpoint );
|
|
|
|
/* This variable can only be read from callbacks */
|
|
|
|
var_Change( pp_vout[i], "viewpoint", VLC_VAR_SETVALUE,
|
2018-06-09 13:46:51 +02:00
|
|
|
(vlc_value_t) { .p_address = NULL } );
|
2019-03-06 19:03:08 +01:00
|
|
|
vout_Release(pp_vout[i]);
|
2017-09-04 11:52:05 +02:00
|
|
|
}
|
|
|
|
free( pp_vout );
|
|
|
|
|
|
|
|
audio_output_t *p_aout = input_resource_HoldAout( priv->p_resource );
|
|
|
|
if( p_aout )
|
|
|
|
{
|
|
|
|
|
|
|
|
var_SetAddress( p_aout, "viewpoint", &priv->viewpoint );
|
|
|
|
/* This variable can only be read from callbacks */
|
|
|
|
var_Change( p_aout, "viewpoint", VLC_VAR_SETVALUE,
|
2018-06-09 13:46:51 +02:00
|
|
|
(vlc_value_t) { .p_address = NULL } );
|
2019-03-06 19:03:08 +01:00
|
|
|
aout_Release(p_aout);
|
2017-09-04 11:52:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-04 11:53:11 +02:00
|
|
|
static void ControlNav( input_thread_t *p_input, int i_type )
|
|
|
|
{
|
|
|
|
input_thread_private_t *priv = input_priv(p_input);
|
|
|
|
|
|
|
|
if( !demux_Control( priv->master->p_demux, i_type
|
|
|
|
- INPUT_CONTROL_NAV_ACTIVATE + DEMUX_NAV_ACTIVATE ) )
|
|
|
|
return; /* The demux handled the navigation control */
|
|
|
|
|
|
|
|
/* Handle Up/Down/Left/Right if the demux can't navigate */
|
2018-04-23 13:40:07 +02:00
|
|
|
vlc_viewpoint_t vp = {0};
|
2017-09-04 12:06:31 +02:00
|
|
|
int vol_direction = 0;
|
|
|
|
int seek_direction = 0;
|
2017-09-04 11:53:11 +02:00
|
|
|
switch( i_type )
|
|
|
|
{
|
|
|
|
case INPUT_CONTROL_NAV_UP:
|
2017-09-04 12:06:31 +02:00
|
|
|
vol_direction = 1;
|
2017-09-04 11:53:11 +02:00
|
|
|
vp.pitch = -1.f;
|
|
|
|
break;
|
|
|
|
case INPUT_CONTROL_NAV_DOWN:
|
2017-09-04 12:06:31 +02:00
|
|
|
vol_direction = -1;
|
2017-09-04 11:53:11 +02:00
|
|
|
vp.pitch = 1.f;
|
|
|
|
break;
|
|
|
|
case INPUT_CONTROL_NAV_LEFT:
|
2017-09-04 12:06:31 +02:00
|
|
|
seek_direction = -1;
|
2017-09-04 11:53:11 +02:00
|
|
|
vp.yaw = -1.f;
|
|
|
|
break;
|
|
|
|
case INPUT_CONTROL_NAV_RIGHT:
|
2017-09-04 12:06:31 +02:00
|
|
|
seek_direction = 1;
|
2017-09-04 11:53:11 +02:00
|
|
|
vp.yaw = 1.f;
|
|
|
|
break;
|
|
|
|
case INPUT_CONTROL_NAV_ACTIVATE:
|
|
|
|
case INPUT_CONTROL_NAV_POPUP:
|
|
|
|
case INPUT_CONTROL_NAV_MENU:
|
|
|
|
return;
|
|
|
|
default:
|
|
|
|
vlc_assert_unreachable();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to change the viewpoint if possible */
|
|
|
|
vout_thread_t **pp_vout;
|
|
|
|
size_t i_vout;
|
|
|
|
bool b_viewpoint_ch = false;
|
|
|
|
input_resource_HoldVouts( priv->p_resource, &pp_vout, &i_vout );
|
|
|
|
for( size_t i = 0; i < i_vout; ++i )
|
|
|
|
{
|
|
|
|
if( !b_viewpoint_ch
|
|
|
|
&& var_GetBool( pp_vout[i], "viewpoint-changeable" ) )
|
|
|
|
b_viewpoint_ch = true;
|
2019-03-06 19:03:08 +01:00
|
|
|
vout_Release(pp_vout[i]);
|
2017-09-04 11:53:11 +02:00
|
|
|
}
|
|
|
|
free( pp_vout );
|
|
|
|
|
|
|
|
if( b_viewpoint_ch )
|
|
|
|
{
|
|
|
|
priv->viewpoint_changed = true;
|
|
|
|
priv->viewpoint.yaw += vp.yaw;
|
|
|
|
priv->viewpoint.pitch += vp.pitch;
|
|
|
|
priv->viewpoint.roll += vp.roll;
|
|
|
|
priv->viewpoint.fov += vp.fov;
|
|
|
|
ViewpointApply( p_input );
|
|
|
|
return;
|
|
|
|
}
|
2017-09-04 12:06:31 +02:00
|
|
|
|
|
|
|
/* Seek or change volume if the input doesn't have navigation or viewpoint */
|
|
|
|
if( seek_direction != 0 )
|
|
|
|
{
|
2018-07-03 14:32:08 +02:00
|
|
|
vlc_tick_t it = vlc_tick_from_sec( seek_direction * var_InheritInteger( p_input, "short-jump-size" ) );
|
2018-11-07 17:07:12 +01:00
|
|
|
Control( p_input, INPUT_CONTROL_JUMP_TIME, (input_control_param_t) {
|
|
|
|
.time.b_fast_seek = false,
|
|
|
|
.time.i_val = it
|
|
|
|
});
|
2017-09-04 12:06:31 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert( vol_direction != 0 );
|
|
|
|
audio_output_t *p_aout = input_resource_HoldAout( priv->p_resource );
|
|
|
|
if( p_aout )
|
|
|
|
{
|
|
|
|
aout_VolumeUpdate( p_aout, vol_direction, NULL );
|
2019-03-06 19:03:08 +01:00
|
|
|
aout_Release(p_aout);
|
2017-09-04 12:06:31 +02:00
|
|
|
}
|
|
|
|
}
|
2017-09-04 11:53:11 +02:00
|
|
|
}
|
|
|
|
|
2017-09-19 12:17:43 +02:00
|
|
|
#ifdef ENABLE_SOUT
|
2018-01-31 15:59:19 +01:00
|
|
|
static void ControlUpdateRenderer( input_thread_t *p_input, bool b_enable )
|
2017-06-19 15:22:51 +02:00
|
|
|
{
|
2018-01-31 15:59:19 +01:00
|
|
|
if( b_enable )
|
2017-06-19 15:22:51 +02:00
|
|
|
{
|
|
|
|
if( InitSout( p_input ) != VLC_SUCCESS )
|
|
|
|
{
|
|
|
|
msg_Err( p_input, "Failed to start sout" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-01-19 18:56:51 +01:00
|
|
|
input_resource_PutSout( input_priv(p_input)->p_resource,
|
|
|
|
input_priv(p_input)->p_sout );
|
2017-06-19 15:22:51 +02:00
|
|
|
input_priv(p_input)->p_sout = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-21 13:08:49 +02:00
|
|
|
static void ControlInsertDemuxFilter( input_thread_t* p_input, const char* psz_demux_chain )
|
|
|
|
{
|
|
|
|
input_source_t *p_inputSource = input_priv(p_input)->master;
|
|
|
|
demux_t *p_filtered_demux = demux_FilterChainNew( p_inputSource->p_demux, psz_demux_chain );
|
|
|
|
if ( p_filtered_demux != NULL )
|
|
|
|
p_inputSource->p_demux = p_filtered_demux;
|
|
|
|
else if ( psz_demux_chain != NULL )
|
|
|
|
msg_Dbg(p_input, "Failed to create demux filter %s", psz_demux_chain);
|
|
|
|
}
|
|
|
|
|
2023-02-22 15:12:30 +01:00
|
|
|
#endif // ENABLE_SOUT
|
|
|
|
|
2021-02-01 16:52:23 +01:00
|
|
|
void input_SetProgramId(input_thread_t *input, int group_id)
|
|
|
|
|
|
|
|
{
|
|
|
|
input_thread_private_t *sys = input_priv(input);
|
|
|
|
|
|
|
|
if (!sys->is_running && !sys->is_stopped)
|
|
|
|
{
|
|
|
|
/* Not running, send the control synchronously since we are sure that
|
|
|
|
* it won't block */
|
|
|
|
es_out_Control(sys->p_es_out_display, ES_OUT_SET_GROUP, group_id);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
input_ControlPushHelper(input, INPUT_CONTROL_SET_PROGRAM,
|
|
|
|
&(vlc_value_t) { .i_int = group_id });
|
|
|
|
}
|
|
|
|
}
|
2018-09-05 09:41:50 +02:00
|
|
|
|
2020-02-20 15:33:54 +01:00
|
|
|
void input_SetEsCatIds(input_thread_t *input, enum es_format_category_e cat,
|
|
|
|
const char *str_ids)
|
|
|
|
{
|
|
|
|
input_thread_private_t *sys = input_priv(input);
|
|
|
|
|
|
|
|
if (!sys->is_running && !sys->is_stopped)
|
|
|
|
{
|
|
|
|
/* Not running, send the control synchronously since we are sure that
|
|
|
|
* it won't block */
|
|
|
|
es_out_SetEsCatIds(sys->p_es_out_display, cat, str_ids);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const input_control_param_t param = {
|
|
|
|
.cat_ids = { cat, str_ids ? strdup(str_ids) : NULL }
|
|
|
|
};
|
|
|
|
input_ControlPush(input, INPUT_CONTROL_SET_ES_CAT_IDS, ¶m);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-28 11:12:06 +01:00
|
|
|
static void ControlSetEsList(input_thread_t *input,
|
|
|
|
enum es_format_category_e cat,
|
|
|
|
vlc_es_id_t **ids)
|
|
|
|
{
|
|
|
|
input_thread_private_t *priv = input_priv(input);
|
|
|
|
|
|
|
|
if (es_out_SetEsList(priv->p_es_out_display, cat, ids) != VLC_SUCCESS)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (ids[0] != NULL && ids[1] == NULL)
|
|
|
|
{
|
2020-02-28 11:17:29 +01:00
|
|
|
/* Update the only demux touched by this change */
|
|
|
|
const input_source_t *source = vlc_es_id_GetSource(ids[0]);
|
|
|
|
assert(source);
|
|
|
|
demux_Control(source->p_demux, DEMUX_SET_ES,
|
2020-02-28 11:12:06 +01:00
|
|
|
vlc_es_id_GetInputId(ids[0]));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-02-28 11:17:29 +01:00
|
|
|
/* Send the updated list for each different sources */
|
2020-02-28 11:12:06 +01:00
|
|
|
size_t count;
|
|
|
|
for (count = 0; ids[count] != NULL; count++);
|
|
|
|
int *array = count ? vlc_alloc(count, sizeof(int)) : NULL;
|
|
|
|
if (!array)
|
|
|
|
return;
|
|
|
|
|
2020-02-28 11:17:29 +01:00
|
|
|
for (int i = 0; i < priv->i_slave + 1; ++ i)
|
|
|
|
{
|
|
|
|
/* For master and all slaves */
|
|
|
|
input_source_t *source = i == 0 ? priv->master : priv->slave[i - 1];
|
|
|
|
|
|
|
|
/* Split the ids array into smaller arrays of ids having the same
|
|
|
|
* source. */
|
|
|
|
size_t set_es_idx = 0;
|
|
|
|
for (size_t ids_idx = 0; ids_idx < count; ++ids_idx)
|
|
|
|
{
|
|
|
|
vlc_es_id_t *id = ids[ids_idx];
|
|
|
|
if (vlc_es_id_GetSource(id) == source)
|
|
|
|
array[set_es_idx++] = vlc_es_id_GetInputId(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update all demuxers */
|
|
|
|
if (set_es_idx > 0)
|
|
|
|
{
|
|
|
|
if (set_es_idx == 1)
|
|
|
|
demux_Control(source->p_demux, DEMUX_SET_ES, array[0]);
|
|
|
|
else
|
|
|
|
demux_Control(source->p_demux, DEMUX_SET_ES_LIST, set_es_idx,
|
|
|
|
array);
|
|
|
|
}
|
|
|
|
}
|
2020-02-28 11:12:06 +01:00
|
|
|
free(array);
|
|
|
|
}
|
|
|
|
|
2009-03-23 20:44:11 +01:00
|
|
|
static bool Control( input_thread_t *p_input,
|
2018-06-25 10:03:48 +02:00
|
|
|
int i_type, input_control_param_t param )
|
2004-06-22 21:29:57 +02:00
|
|
|
{
|
2018-09-03 13:50:42 +02:00
|
|
|
input_thread_private_t *priv = input_priv(p_input);
|
2018-06-20 08:37:11 +02:00
|
|
|
const vlc_tick_t i_control_date = vlc_tick_now();
|
2008-11-20 21:49:51 +01:00
|
|
|
/* FIXME b_force_update is abused, it should be carefully checked */
|
2008-04-14 00:08:29 +02:00
|
|
|
bool b_force_update = false;
|
2004-06-22 21:29:57 +02:00
|
|
|
|
|
|
|
switch( i_type )
|
|
|
|
{
|
|
|
|
case INPUT_CONTROL_SET_POSITION:
|
2018-10-10 13:20:02 +02:00
|
|
|
case INPUT_CONTROL_JUMP_POSITION:
|
|
|
|
{
|
|
|
|
const bool absolute = i_type == INPUT_CONTROL_SET_POSITION;
|
2018-09-03 13:50:42 +02:00
|
|
|
if( priv->b_recording )
|
2008-08-26 12:54:18 +02:00
|
|
|
{
|
2016-06-25 17:45:57 +02:00
|
|
|
msg_Err( p_input, "INPUT_CONTROL_SET_POSITION ignored while recording" );
|
2008-08-26 12:54:18 +02:00
|
|
|
break;
|
|
|
|
}
|
2014-08-13 20:03:29 +02:00
|
|
|
|
2006-09-21 17:51:31 +02:00
|
|
|
/* Reset the decoders states and clock sync (before calling the demuxer */
|
2018-09-03 13:50:42 +02:00
|
|
|
es_out_Control( priv->p_es_out, ES_OUT_RESET_PCR );
|
2022-08-03 13:18:40 +02:00
|
|
|
if( demux_SetPosition( priv->master->p_demux, param.pos.f_val,
|
2018-10-10 13:20:02 +02:00
|
|
|
!param.pos.b_fast_seek, absolute ) )
|
2004-06-22 21:29:57 +02:00
|
|
|
{
|
2016-06-25 17:45:57 +02:00
|
|
|
msg_Err( p_input, "INPUT_CONTROL_SET_POSITION "
|
2018-09-05 09:41:50 +02:00
|
|
|
"%s%2.1f%% failed",
|
2018-10-10 13:20:02 +02:00
|
|
|
absolute ? "@" : param.pos.f_val >= 0 ? "+" : "",
|
2018-09-05 09:41:50 +02:00
|
|
|
param.pos.f_val * 100.f );
|
2004-06-22 21:29:57 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-09-03 13:50:42 +02:00
|
|
|
if( priv->i_slave > 0 )
|
2004-06-25 00:21:36 +02:00
|
|
|
SlaveSeek( p_input );
|
2018-09-03 13:50:42 +02:00
|
|
|
priv->master->b_eof = false;
|
2004-06-25 00:21:36 +02:00
|
|
|
|
2008-04-14 00:08:29 +02:00
|
|
|
b_force_update = true;
|
2004-06-22 21:29:57 +02:00
|
|
|
}
|
|
|
|
break;
|
2018-10-10 13:20:02 +02:00
|
|
|
}
|
2004-06-22 21:29:57 +02:00
|
|
|
|
|
|
|
case INPUT_CONTROL_SET_TIME:
|
2018-10-10 13:20:02 +02:00
|
|
|
case INPUT_CONTROL_JUMP_TIME:
|
2004-06-22 21:29:57 +02:00
|
|
|
{
|
2018-10-10 13:20:02 +02:00
|
|
|
const bool absolute = i_type == INPUT_CONTROL_SET_TIME;
|
2004-06-22 21:29:57 +02:00
|
|
|
int i_ret;
|
|
|
|
|
2018-09-03 13:50:42 +02:00
|
|
|
if( priv->b_recording )
|
2008-08-26 12:54:18 +02:00
|
|
|
{
|
2016-06-25 17:45:57 +02:00
|
|
|
msg_Err( p_input, "INPUT_CONTROL_SET_TIME ignored while recording" );
|
2008-08-26 12:54:18 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-09-21 17:51:31 +02:00
|
|
|
/* Reset the decoders states and clock sync (before calling the demuxer */
|
2018-09-03 13:50:42 +02:00
|
|
|
es_out_Control( priv->p_es_out, ES_OUT_RESET_PCR );
|
2005-02-21 10:03:07 +01:00
|
|
|
|
2018-09-05 09:40:22 +02:00
|
|
|
i_ret = demux_SetTime( priv->master->p_demux, param.time.i_val,
|
2018-10-10 13:20:02 +02:00
|
|
|
!param.time.b_fast_seek, absolute );
|
2004-06-22 21:29:57 +02:00
|
|
|
if( i_ret )
|
|
|
|
{
|
2018-05-05 16:16:51 +02:00
|
|
|
vlc_tick_t i_length;
|
2004-06-22 21:29:57 +02:00
|
|
|
|
2005-10-16 22:07:15 +02:00
|
|
|
/* Emulate it with a SET_POS */
|
2018-09-03 13:50:42 +02:00
|
|
|
if( !demux_Control( priv->master->p_demux,
|
2009-09-03 22:25:20 +02:00
|
|
|
DEMUX_GET_LENGTH, &i_length ) && i_length > 0 )
|
2004-06-22 21:29:57 +02:00
|
|
|
{
|
2018-09-05 09:40:22 +02:00
|
|
|
double f_pos = (double)param.time.i_val / (double)i_length;
|
|
|
|
i_ret = demux_SetPosition( priv->master->p_demux, f_pos,
|
|
|
|
!param.time.b_fast_seek,
|
2018-10-10 13:20:02 +02:00
|
|
|
absolute );
|
2004-06-22 21:29:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if( i_ret )
|
|
|
|
{
|
2018-09-05 09:41:50 +02:00
|
|
|
msg_Warn( p_input, "INPUT_CONTROL_SET_TIME %s%"PRId64
|
|
|
|
" failed or not possible",
|
2018-10-10 13:20:02 +02:00
|
|
|
absolute ? "@" : param.time.i_val >= 0 ? "+" : "",
|
2018-09-05 09:41:50 +02:00
|
|
|
param.time.i_val );
|
2004-06-22 21:29:57 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-09-03 13:50:42 +02:00
|
|
|
if( priv->i_slave > 0 )
|
2004-06-25 00:21:36 +02:00
|
|
|
SlaveSeek( p_input );
|
2018-09-03 13:50:42 +02:00
|
|
|
priv->master->b_eof = false;
|
2004-06-25 00:21:36 +02:00
|
|
|
|
2008-04-14 00:08:29 +02:00
|
|
|
b_force_update = true;
|
2004-06-22 21:29:57 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case INPUT_CONTROL_SET_STATE:
|
2018-06-25 10:03:48 +02:00
|
|
|
switch( param.val.i_int )
|
2004-06-22 21:29:57 +02:00
|
|
|
{
|
2015-03-30 16:57:42 +02:00
|
|
|
case PLAYING_S:
|
2018-09-03 13:50:42 +02:00
|
|
|
if( priv->i_state == PAUSE_S )
|
2015-03-30 16:57:42 +02:00
|
|
|
{
|
|
|
|
ControlUnpause( p_input, i_control_date );
|
|
|
|
b_force_update = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PAUSE_S:
|
2018-09-03 13:50:42 +02:00
|
|
|
if( priv->i_state == PLAYING_S )
|
2015-03-30 16:57:42 +02:00
|
|
|
{
|
|
|
|
ControlPause( p_input, i_control_date );
|
|
|
|
b_force_update = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
msg_Err( p_input, "invalid INPUT_CONTROL_SET_STATE" );
|
2004-06-22 21:29:57 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case INPUT_CONTROL_SET_RATE:
|
|
|
|
{
|
2008-11-20 19:21:22 +01:00
|
|
|
/* Get rate and direction */
|
2019-02-15 15:38:39 +01:00
|
|
|
float rate = fabsf( param.val.f_float );
|
2019-06-05 13:54:35 +02:00
|
|
|
int i_rate_sign = param.val.f_float < 0 ? -1 : 1;
|
2004-06-22 21:29:57 +02:00
|
|
|
|
2008-11-20 19:21:22 +01:00
|
|
|
/* Check rate bound */
|
2019-02-15 16:11:50 +01:00
|
|
|
if( rate > INPUT_RATE_MAX )
|
2004-06-22 21:29:57 +02:00
|
|
|
{
|
2019-02-15 15:38:39 +01:00
|
|
|
msg_Info( p_input, "cannot set rate faster" );
|
2019-02-15 16:11:50 +01:00
|
|
|
rate = INPUT_RATE_MAX;
|
2004-06-22 21:29:57 +02:00
|
|
|
}
|
2019-02-15 16:11:50 +01:00
|
|
|
else if( rate < INPUT_RATE_MIN )
|
2004-06-22 21:29:57 +02:00
|
|
|
{
|
2019-02-15 15:38:39 +01:00
|
|
|
msg_Info( p_input, "cannot set rate slower" );
|
2019-02-15 16:11:50 +01:00
|
|
|
rate = INPUT_RATE_MIN;
|
2004-06-22 21:29:57 +02:00
|
|
|
}
|
2008-11-20 19:21:22 +01:00
|
|
|
|
|
|
|
/* Apply direction */
|
|
|
|
if( i_rate_sign < 0 )
|
|
|
|
{
|
2018-09-03 13:50:42 +02:00
|
|
|
if( priv->master->b_rescale_ts )
|
2008-11-20 19:21:22 +01:00
|
|
|
{
|
|
|
|
msg_Dbg( p_input, "cannot set negative rate" );
|
2019-02-15 15:38:39 +01:00
|
|
|
rate = priv->rate;
|
|
|
|
assert( rate > 0 );
|
2008-11-20 19:21:22 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-02-15 15:38:39 +01:00
|
|
|
rate *= i_rate_sign;
|
2008-11-20 19:21:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-15 15:38:39 +01:00
|
|
|
if( rate != 1.f &&
|
2021-04-27 13:33:21 +02:00
|
|
|
( ( !priv->master->b_can_rate_control && !priv->master->b_rescale_ts ) ||
|
2018-09-03 13:50:42 +02:00
|
|
|
( priv->p_sout && !priv->b_out_pace_control ) ) )
|
2004-06-22 21:29:57 +02:00
|
|
|
{
|
|
|
|
msg_Dbg( p_input, "cannot change rate" );
|
2019-02-15 15:38:39 +01:00
|
|
|
rate = 1.f;
|
2004-06-22 21:29:57 +02:00
|
|
|
}
|
2019-02-15 15:38:39 +01:00
|
|
|
if( rate != priv->rate &&
|
2021-04-27 13:33:21 +02:00
|
|
|
!priv->master->b_can_pace_control && priv->master->b_can_rate_control )
|
2007-12-11 21:49:56 +01:00
|
|
|
{
|
2018-09-03 13:50:42 +02:00
|
|
|
if( !priv->master->b_rescale_ts )
|
|
|
|
es_out_Control( priv->p_es_out, ES_OUT_RESET_PCR );
|
2013-08-27 21:40:06 +02:00
|
|
|
|
2018-09-03 13:50:42 +02:00
|
|
|
if( demux_Control( priv->master->p_demux, DEMUX_SET_RATE,
|
2019-02-15 15:38:39 +01:00
|
|
|
&rate ) )
|
2007-12-11 21:49:56 +01:00
|
|
|
{
|
|
|
|
msg_Warn( p_input, "ACCESS/DEMUX_SET_RATE failed" );
|
2019-02-15 15:38:39 +01:00
|
|
|
rate = priv->rate;
|
2007-12-11 21:49:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* */
|
2019-02-15 15:38:39 +01:00
|
|
|
if( rate != priv->rate )
|
2004-06-22 21:29:57 +02:00
|
|
|
{
|
2019-02-15 15:38:39 +01:00
|
|
|
priv->rate = rate;
|
|
|
|
input_SendEventRate( p_input, rate );
|
2007-03-02 20:42:22 +01:00
|
|
|
|
2018-09-03 13:50:42 +02:00
|
|
|
if( priv->master->b_rescale_ts )
|
2008-11-15 20:28:08 +01:00
|
|
|
{
|
2021-04-27 13:33:21 +02:00
|
|
|
const float rate_source = (priv->master->b_can_pace_control ||
|
|
|
|
priv->master->b_can_rate_control ) ? rate : 1.f;
|
2019-02-15 15:38:39 +01:00
|
|
|
es_out_SetRate( priv->p_es_out, rate_source, rate );
|
2008-11-15 20:28:08 +01:00
|
|
|
}
|
2004-06-22 21:29:57 +02:00
|
|
|
|
2008-04-14 00:08:29 +02:00
|
|
|
b_force_update = true;
|
2004-06-22 21:29:57 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case INPUT_CONTROL_SET_PROGRAM:
|
|
|
|
/* No need to force update, es_out does it if needed */
|
2018-09-03 13:50:42 +02:00
|
|
|
es_out_Control( priv->p_es_out,
|
2018-06-25 10:03:48 +02:00
|
|
|
ES_OUT_SET_GROUP, (int)param.val.i_int );
|
2004-08-25 22:08:23 +02:00
|
|
|
|
2018-06-25 10:03:48 +02:00
|
|
|
if( param.val.i_int == 0 )
|
2018-09-03 13:50:42 +02:00
|
|
|
demux_Control( priv->master->p_demux,
|
2018-06-09 11:31:44 +02:00
|
|
|
DEMUX_SET_GROUP_DEFAULT );
|
2018-06-09 11:04:12 +02:00
|
|
|
else
|
2018-09-03 13:50:42 +02:00
|
|
|
demux_Control( priv->master->p_demux,
|
2018-06-09 11:46:47 +02:00
|
|
|
DEMUX_SET_GROUP_LIST,
|
2018-06-25 10:03:48 +02:00
|
|
|
(size_t)1, &(const int){ param.val.i_int });
|
2004-06-22 21:29:57 +02:00
|
|
|
break;
|
|
|
|
|
2018-08-29 12:01:57 +02:00
|
|
|
case INPUT_CONTROL_SET_ES:
|
2020-02-27 15:33:28 +01:00
|
|
|
if( es_out_SetEs( priv->p_es_out_display, param.id ) == VLC_SUCCESS )
|
2020-02-28 11:17:29 +01:00
|
|
|
{
|
|
|
|
const input_source_t *source = vlc_es_id_GetSource( param.id );
|
|
|
|
assert( source );
|
|
|
|
demux_Control( source->p_demux, DEMUX_SET_ES,
|
2018-08-29 12:01:57 +02:00
|
|
|
vlc_es_id_GetInputId( param.id ) );
|
2020-02-28 11:17:29 +01:00
|
|
|
}
|
2018-08-29 12:01:57 +02:00
|
|
|
break;
|
2019-06-20 13:29:58 +02:00
|
|
|
case INPUT_CONTROL_SET_ES_LIST:
|
2020-02-28 11:12:06 +01:00
|
|
|
ControlSetEsList( p_input, param.list.cat, param.list.ids );
|
2019-06-20 13:29:58 +02:00
|
|
|
break;
|
2018-08-29 12:01:57 +02:00
|
|
|
case INPUT_CONTROL_UNSET_ES:
|
2020-02-27 15:33:28 +01:00
|
|
|
es_out_UnsetEs( priv->p_es_out_display, param.id );
|
2018-08-29 12:01:57 +02:00
|
|
|
break;
|
|
|
|
case INPUT_CONTROL_RESTART_ES:
|
2020-02-27 15:33:28 +01:00
|
|
|
es_out_RestartEs( priv->p_es_out_display, param.id );
|
2018-08-29 12:01:57 +02:00
|
|
|
break;
|
2020-02-20 15:33:54 +01:00
|
|
|
case INPUT_CONTROL_SET_ES_CAT_IDS:
|
|
|
|
es_out_SetEsCatIds( priv->p_es_out_display, param.cat_ids.cat,
|
|
|
|
param.cat_ids.str_ids );
|
|
|
|
break;
|
2018-08-29 12:01:57 +02:00
|
|
|
|
2016-11-10 18:24:18 +01:00
|
|
|
case INPUT_CONTROL_SET_VIEWPOINT:
|
2017-07-24 19:17:29 +02:00
|
|
|
case INPUT_CONTROL_SET_INITIAL_VIEWPOINT:
|
2016-11-10 18:24:18 +01:00
|
|
|
case INPUT_CONTROL_UPDATE_VIEWPOINT:
|
2017-07-24 19:17:29 +02:00
|
|
|
if ( i_type == INPUT_CONTROL_SET_INITIAL_VIEWPOINT )
|
|
|
|
{
|
|
|
|
|
|
|
|
/* Set the initial viewpoint if it had not been changed by the
|
|
|
|
* user. */
|
|
|
|
if( !priv->viewpoint_changed )
|
2018-06-25 10:03:48 +02:00
|
|
|
priv->viewpoint = param.viewpoint;
|
2017-07-24 19:17:29 +02:00
|
|
|
/* Update viewpoints of aout and every vouts in all cases. */
|
|
|
|
}
|
|
|
|
else if ( i_type == INPUT_CONTROL_SET_VIEWPOINT)
|
|
|
|
{
|
|
|
|
priv->viewpoint_changed = true;
|
2018-06-25 10:03:48 +02:00
|
|
|
priv->viewpoint = param.viewpoint;
|
2017-07-24 19:17:29 +02:00
|
|
|
}
|
2016-11-10 18:24:18 +01:00
|
|
|
else
|
|
|
|
{
|
2017-07-24 19:17:29 +02:00
|
|
|
priv->viewpoint_changed = true;
|
2018-06-25 10:03:48 +02:00
|
|
|
priv->viewpoint.yaw += param.viewpoint.yaw;
|
|
|
|
priv->viewpoint.pitch += param.viewpoint.pitch;
|
|
|
|
priv->viewpoint.roll += param.viewpoint.roll;
|
|
|
|
priv->viewpoint.fov += param.viewpoint.fov;
|
2016-11-10 18:24:18 +01:00
|
|
|
}
|
|
|
|
|
2017-09-04 11:52:05 +02:00
|
|
|
ViewpointApply( p_input );
|
2016-11-10 18:24:18 +01:00
|
|
|
break;
|
|
|
|
|
2019-07-11 16:27:57 +02:00
|
|
|
case INPUT_CONTROL_SET_CATEGORY_DELAY:
|
|
|
|
assert(param.cat_delay.cat == AUDIO_ES
|
|
|
|
|| param.cat_delay.cat == SPU_ES);
|
|
|
|
es_out_SetDelay(priv->p_es_out_display,
|
|
|
|
param.cat_delay.cat, param.cat_delay.delay);
|
|
|
|
break;
|
|
|
|
case INPUT_CONTROL_SET_ES_DELAY:
|
|
|
|
assert(param.es_delay.id);
|
2020-02-27 15:21:29 +01:00
|
|
|
es_out_SetEsDelay(priv->p_es_out_display, param.es_delay.id,
|
2019-07-11 16:27:57 +02:00
|
|
|
param.es_delay.delay);
|
|
|
|
break;
|
|
|
|
|
2004-06-22 21:29:57 +02:00
|
|
|
case INPUT_CONTROL_SET_TITLE:
|
|
|
|
case INPUT_CONTROL_SET_TITLE_NEXT:
|
|
|
|
case INPUT_CONTROL_SET_TITLE_PREV:
|
2013-04-17 18:27:17 +02:00
|
|
|
{
|
2018-09-03 13:50:42 +02:00
|
|
|
if( priv->b_recording )
|
2008-08-26 12:54:18 +02:00
|
|
|
{
|
|
|
|
msg_Err( p_input, "INPUT_CONTROL_SET_TITLE(*) ignored while recording" );
|
|
|
|
break;
|
|
|
|
}
|
2018-09-03 13:50:42 +02:00
|
|
|
if( priv->master->i_title <= 0 )
|
2013-04-17 18:27:17 +02:00
|
|
|
break;
|
2004-06-22 21:29:57 +02:00
|
|
|
|
2018-09-03 13:50:42 +02:00
|
|
|
int i_title = demux_GetTitle( priv->master->p_demux );
|
2013-04-17 18:27:17 +02:00
|
|
|
if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
|
|
|
|
i_title--;
|
|
|
|
else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
|
|
|
|
i_title++;
|
|
|
|
else
|
2018-06-25 10:03:48 +02:00
|
|
|
i_title = param.val.i_int;
|
2018-09-03 13:50:42 +02:00
|
|
|
if( i_title < 0 || i_title >= priv->master->i_title )
|
2013-04-17 18:27:17 +02:00
|
|
|
break;
|
2006-03-28 22:29:28 +02:00
|
|
|
|
2018-09-03 13:50:42 +02:00
|
|
|
es_out_Control( priv->p_es_out, ES_OUT_RESET_PCR );
|
|
|
|
demux_Control( priv->master->p_demux,
|
2013-08-26 20:58:02 +02:00
|
|
|
DEMUX_SET_TITLE, i_title );
|
2004-06-22 21:29:57 +02:00
|
|
|
break;
|
2013-04-17 18:27:17 +02:00
|
|
|
}
|
2004-06-22 21:29:57 +02:00
|
|
|
case INPUT_CONTROL_SET_SEEKPOINT:
|
|
|
|
case INPUT_CONTROL_SET_SEEKPOINT_NEXT:
|
|
|
|
case INPUT_CONTROL_SET_SEEKPOINT_PREV:
|
2013-04-17 18:35:02 +02:00
|
|
|
{
|
2018-09-03 13:50:42 +02:00
|
|
|
if( priv->b_recording )
|
2008-08-26 12:54:18 +02:00
|
|
|
{
|
|
|
|
msg_Err( p_input, "INPUT_CONTROL_SET_SEEKPOINT(*) ignored while recording" );
|
|
|
|
break;
|
|
|
|
}
|
2018-09-03 13:50:42 +02:00
|
|
|
if( priv->master->i_title <= 0 )
|
2013-04-17 18:35:02 +02:00
|
|
|
break;
|
2008-08-26 12:54:18 +02:00
|
|
|
|
2018-09-03 13:50:42 +02:00
|
|
|
demux_t *p_demux = priv->master->p_demux;
|
2004-06-22 21:29:57 +02:00
|
|
|
|
2016-06-07 11:15:16 +02:00
|
|
|
int i_title = demux_GetTitle( p_demux );
|
|
|
|
int i_seekpoint = demux_GetSeekpoint( p_demux );
|
2013-04-17 18:35:02 +02:00
|
|
|
|
|
|
|
if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
|
|
|
|
{
|
2018-05-05 17:12:06 +02:00
|
|
|
vlc_tick_t i_seekpoint_time = priv->master->title[i_title]->seekpoint[i_seekpoint]->i_time_offset;
|
2018-05-05 17:51:16 +02:00
|
|
|
vlc_tick_t i_input_time = var_GetInteger( p_input, "time" );
|
2013-04-17 18:35:02 +02:00
|
|
|
if( i_seekpoint_time >= 0 && i_input_time >= 0 )
|
2005-03-08 10:06:27 +01:00
|
|
|
{
|
2018-05-05 17:10:01 +02:00
|
|
|
if( i_input_time < i_seekpoint_time + VLC_TICK_FROM_SEC(3) )
|
2005-03-08 10:06:27 +01:00
|
|
|
i_seekpoint--;
|
|
|
|
}
|
2004-06-22 21:29:57 +02:00
|
|
|
else
|
2013-04-17 18:35:02 +02:00
|
|
|
i_seekpoint--;
|
2004-06-22 21:29:57 +02:00
|
|
|
}
|
2013-04-17 18:35:02 +02:00
|
|
|
else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT )
|
|
|
|
i_seekpoint++;
|
|
|
|
else
|
2018-06-25 10:03:48 +02:00
|
|
|
i_seekpoint = param.val.i_int;
|
2013-04-17 18:35:02 +02:00
|
|
|
if( i_seekpoint < 0
|
2018-09-03 13:50:42 +02:00
|
|
|
|| i_seekpoint >= priv->master->title[i_title]->i_seekpoint )
|
2013-04-17 18:35:02 +02:00
|
|
|
break;
|
|
|
|
|
2018-09-03 13:50:42 +02:00
|
|
|
es_out_Control( priv->p_es_out, ES_OUT_RESET_PCR );
|
|
|
|
demux_Control( priv->master->p_demux,
|
2013-08-26 20:58:02 +02:00
|
|
|
DEMUX_SET_SEEKPOINT, i_seekpoint );
|
2013-04-17 18:35:02 +02:00
|
|
|
input_SendEventSeekpoint( p_input, i_title, i_seekpoint );
|
2020-02-15 18:48:02 +01:00
|
|
|
if( priv->i_slave > 0 )
|
|
|
|
SlaveSeek( p_input );
|
2004-06-22 21:29:57 +02:00
|
|
|
break;
|
2013-04-17 18:35:02 +02:00
|
|
|
}
|
2004-06-22 21:29:57 +02:00
|
|
|
|
2004-11-22 10:57:50 +01:00
|
|
|
case INPUT_CONTROL_ADD_SLAVE:
|
2018-06-25 10:03:48 +02:00
|
|
|
if( param.val.p_address )
|
2004-11-22 10:57:50 +01:00
|
|
|
{
|
2018-06-25 10:03:48 +02:00
|
|
|
input_item_slave_t *p_item_slave = param.val.p_address;
|
2016-06-07 17:19:19 +02:00
|
|
|
unsigned i_flags = SLAVE_ADD_CANFAIL | SLAVE_ADD_SET_TIME;
|
|
|
|
if( p_item_slave->b_forced )
|
|
|
|
i_flags |= SLAVE_ADD_FORCED;
|
2016-05-27 11:41:06 +02:00
|
|
|
|
2016-06-07 17:19:19 +02:00
|
|
|
if( input_SlaveSourceAdd( p_input, p_item_slave->i_type,
|
|
|
|
p_item_slave->psz_uri, i_flags )
|
|
|
|
== VLC_SUCCESS )
|
|
|
|
{
|
2016-05-27 11:41:06 +02:00
|
|
|
/* Update item slaves */
|
2018-09-03 13:50:42 +02:00
|
|
|
input_item_AddSlave( priv->p_item, p_item_slave );
|
2016-06-07 17:19:19 +02:00
|
|
|
/* The slave is now owned by the item */
|
2018-06-25 10:03:48 +02:00
|
|
|
param.val.p_address = NULL;
|
2015-10-24 19:57:33 +02:00
|
|
|
}
|
2004-11-22 10:57:50 +01:00
|
|
|
}
|
|
|
|
break;
|
2018-10-17 14:43:14 +02:00
|
|
|
case INPUT_CONTROL_SET_SUBS_FPS:
|
|
|
|
RequestSubRate( p_input, param.val.f_float );
|
|
|
|
input_SendEventSubsFPS( p_input, param.val.f_float );
|
|
|
|
break;
|
2004-11-22 10:57:50 +01:00
|
|
|
|
2008-08-26 12:54:18 +02:00
|
|
|
case INPUT_CONTROL_SET_RECORD_STATE:
|
2022-08-10 15:43:58 +02:00
|
|
|
{
|
|
|
|
bool enabled = param.record_state.enabled;
|
|
|
|
const char *dir_path = param.record_state.dir_path;
|
|
|
|
if( !!priv->b_recording != enabled )
|
2008-08-26 12:54:18 +02:00
|
|
|
{
|
2018-09-03 13:50:42 +02:00
|
|
|
if( priv->master->b_can_stream_record )
|
2008-08-26 12:54:18 +02:00
|
|
|
{
|
2018-09-03 13:50:42 +02:00
|
|
|
if( demux_Control( priv->master->p_demux,
|
2022-08-10 15:43:58 +02:00
|
|
|
DEMUX_SET_RECORD_STATE, enabled, dir_path ) )
|
|
|
|
enabled = false;
|
2008-08-26 12:54:18 +02:00
|
|
|
}
|
2008-08-26 23:10:56 +02:00
|
|
|
else
|
|
|
|
{
|
2022-08-10 15:43:58 +02:00
|
|
|
if( es_out_SetRecordState( priv->p_es_out_display, enabled, dir_path ) )
|
|
|
|
enabled = false;
|
2008-08-26 23:10:56 +02:00
|
|
|
}
|
2022-08-10 15:43:58 +02:00
|
|
|
priv->b_recording = enabled;
|
2008-08-26 12:54:18 +02:00
|
|
|
|
2022-08-10 15:43:58 +02:00
|
|
|
input_SendEventRecord( p_input, enabled );
|
2008-08-26 12:54:18 +02:00
|
|
|
|
|
|
|
b_force_update = true;
|
|
|
|
}
|
|
|
|
break;
|
2022-08-10 15:43:58 +02:00
|
|
|
}
|
2008-08-26 12:54:18 +02:00
|
|
|
|
2008-10-13 23:13:29 +02:00
|
|
|
case INPUT_CONTROL_SET_FRAME_NEXT:
|
2018-09-03 13:50:42 +02:00
|
|
|
if( priv->i_state == PAUSE_S )
|
2008-10-13 23:13:29 +02:00
|
|
|
{
|
2018-09-03 13:50:42 +02:00
|
|
|
es_out_SetFrameNext( priv->p_es_out );
|
2008-10-13 23:13:29 +02:00
|
|
|
}
|
2018-09-03 13:50:42 +02:00
|
|
|
else if( priv->i_state == PLAYING_S )
|
2008-10-13 23:13:29 +02:00
|
|
|
{
|
|
|
|
ControlPause( p_input, i_control_date );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msg_Err( p_input, "invalid state for frame next" );
|
|
|
|
}
|
|
|
|
b_force_update = true;
|
|
|
|
break;
|
|
|
|
|
2017-07-19 10:55:14 +02:00
|
|
|
case INPUT_CONTROL_SET_RENDERER:
|
|
|
|
{
|
2017-09-19 12:17:43 +02:00
|
|
|
#ifdef ENABLE_SOUT
|
2018-06-25 10:03:48 +02:00
|
|
|
vlc_renderer_item_t *p_item = param.val.p_address;
|
2017-07-19 10:55:14 +02:00
|
|
|
input_thread_private_t *p_priv = input_priv( p_input );
|
|
|
|
// We do not support switching from a renderer to another for now
|
|
|
|
if ( p_item == NULL && p_priv->p_renderer == NULL )
|
|
|
|
break;
|
|
|
|
|
2020-02-28 15:15:38 +01:00
|
|
|
vlc_es_id_t **context;
|
2020-02-27 14:05:19 +01:00
|
|
|
if( es_out_StopAllEs( priv->p_es_out_display, &context ) != VLC_SUCCESS )
|
2018-02-14 11:59:05 +01:00
|
|
|
break;
|
|
|
|
|
2017-07-19 10:55:14 +02:00
|
|
|
if ( p_priv->p_renderer )
|
|
|
|
{
|
2018-01-31 15:59:19 +01:00
|
|
|
ControlUpdateRenderer( p_input, false );
|
2017-07-19 10:55:14 +02:00
|
|
|
demux_FilterDisable( p_priv->master->p_demux,
|
|
|
|
vlc_renderer_item_demux_filter( p_priv->p_renderer ) );
|
|
|
|
vlc_renderer_item_release( p_priv->p_renderer );
|
|
|
|
p_priv->p_renderer = NULL;
|
|
|
|
}
|
|
|
|
if( p_item != NULL )
|
|
|
|
{
|
|
|
|
p_priv->p_renderer = vlc_renderer_item_hold( p_item );
|
2018-01-31 15:59:19 +01:00
|
|
|
ControlUpdateRenderer( p_input, true );
|
2017-07-19 10:55:14 +02:00
|
|
|
if( !demux_FilterEnable( p_priv->master->p_demux,
|
|
|
|
vlc_renderer_item_demux_filter( p_priv->p_renderer ) ) )
|
|
|
|
{
|
|
|
|
ControlInsertDemuxFilter( p_input,
|
|
|
|
vlc_renderer_item_demux_filter( p_item ) );
|
|
|
|
}
|
|
|
|
}
|
2020-02-27 14:05:19 +01:00
|
|
|
es_out_StartAllEs( priv->p_es_out_display, context );
|
2017-09-19 12:17:43 +02:00
|
|
|
#endif
|
2017-07-19 10:55:14 +02:00
|
|
|
break;
|
|
|
|
}
|
2018-10-16 16:05:57 +02:00
|
|
|
case INPUT_CONTROL_SET_VBI_PAGE:
|
2020-02-27 14:05:19 +01:00
|
|
|
es_out_SetVbiPage( priv->p_es_out_display, param.vbi_page.id,
|
|
|
|
param.vbi_page.page );
|
2018-10-16 16:05:57 +02:00
|
|
|
break;
|
|
|
|
case INPUT_CONTROL_SET_VBI_TRANSPARENCY:
|
2020-02-27 14:05:19 +01:00
|
|
|
es_out_SetVbiTransparency( priv->p_es_out_display,
|
|
|
|
param.vbi_transparency.id,
|
|
|
|
param.vbi_transparency.enabled );
|
2018-10-16 16:05:57 +02:00
|
|
|
break;
|
2008-12-03 23:58:10 +01:00
|
|
|
|
2013-02-01 16:54:34 +01:00
|
|
|
case INPUT_CONTROL_NAV_ACTIVATE:
|
|
|
|
case INPUT_CONTROL_NAV_UP:
|
|
|
|
case INPUT_CONTROL_NAV_DOWN:
|
|
|
|
case INPUT_CONTROL_NAV_LEFT:
|
|
|
|
case INPUT_CONTROL_NAV_RIGHT:
|
2015-11-20 11:29:59 +01:00
|
|
|
case INPUT_CONTROL_NAV_POPUP:
|
2016-05-13 10:51:23 +02:00
|
|
|
case INPUT_CONTROL_NAV_MENU:
|
2017-09-04 11:53:11 +02:00
|
|
|
ControlNav( p_input, i_type );
|
2013-02-01 16:54:34 +01:00
|
|
|
break;
|
|
|
|
|
2004-06-22 21:29:57 +02:00
|
|
|
default:
|
|
|
|
msg_Err( p_input, "not yet implemented" );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-06-25 10:03:48 +02:00
|
|
|
ControlRelease( i_type, ¶m );
|
2004-06-22 21:29:57 +02:00
|
|
|
return b_force_update;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
2008-12-01 22:53:25 +01:00
|
|
|
* UpdateTitleSeekpoint
|
2004-06-22 21:29:57 +02:00
|
|
|
*****************************************************************************/
|
2008-11-20 21:49:51 +01:00
|
|
|
static int UpdateTitleSeekpoint( input_thread_t *p_input,
|
|
|
|
int i_title, int i_seekpoint )
|
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
int i_title_end = input_priv(p_input)->master->i_title_end -
|
|
|
|
input_priv(p_input)->master->i_title_offset;
|
|
|
|
int i_seekpoint_end = input_priv(p_input)->master->i_seekpoint_end -
|
|
|
|
input_priv(p_input)->master->i_seekpoint_offset;
|
2008-11-20 21:49:51 +01:00
|
|
|
|
|
|
|
if( i_title_end >= 0 && i_seekpoint_end >= 0 )
|
|
|
|
{
|
|
|
|
if( i_title > i_title_end ||
|
|
|
|
( i_title == i_title_end && i_seekpoint > i_seekpoint_end ) )
|
2016-03-30 08:55:47 +02:00
|
|
|
return VLC_DEMUXER_EOF;
|
2008-11-20 21:49:51 +01:00
|
|
|
}
|
|
|
|
else if( i_seekpoint_end >= 0 )
|
|
|
|
{
|
|
|
|
if( i_seekpoint > i_seekpoint_end )
|
2016-03-30 08:55:47 +02:00
|
|
|
return VLC_DEMUXER_EOF;
|
2008-11-20 21:49:51 +01:00
|
|
|
}
|
|
|
|
else if( i_title_end >= 0 )
|
|
|
|
{
|
|
|
|
if( i_title > i_title_end )
|
2016-03-30 08:55:47 +02:00
|
|
|
return VLC_DEMUXER_EOF;
|
2008-11-20 21:49:51 +01:00
|
|
|
}
|
2016-03-30 08:55:47 +02:00
|
|
|
return VLC_DEMUXER_SUCCESS;
|
2008-11-20 21:49:51 +01:00
|
|
|
}
|
2008-12-01 22:53:25 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* Update*FromDemux:
|
|
|
|
*****************************************************************************/
|
|
|
|
static int UpdateTitleSeekpointFromDemux( input_thread_t *p_input )
|
2004-06-22 21:29:57 +02:00
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
demux_t *p_demux = input_priv(p_input)->master->p_demux;
|
2004-06-22 21:29:57 +02:00
|
|
|
|
2008-11-20 21:49:51 +01:00
|
|
|
/* TODO event-like */
|
2016-06-09 19:58:55 +02:00
|
|
|
if( demux_TestAndClearFlags( p_demux, INPUT_UPDATE_TITLE ) )
|
2018-09-11 17:50:09 +02:00
|
|
|
input_SendEventTitle( p_input, &(struct vlc_input_event_title) {
|
|
|
|
.action = VLC_INPUT_TITLE_SELECTED,
|
|
|
|
.selected_idx = demux_GetTitle( p_demux ),
|
|
|
|
});
|
2004-06-22 21:29:57 +02:00
|
|
|
|
2016-06-09 19:58:55 +02:00
|
|
|
if( demux_TestAndClearFlags( p_demux, INPUT_UPDATE_SEEKPOINT ) )
|
|
|
|
input_SendEventSeekpoint( p_input, demux_GetTitle( p_demux ),
|
|
|
|
demux_GetSeekpoint( p_demux ) );
|
2004-08-21 01:37:40 +02:00
|
|
|
|
2015-10-24 19:10:22 +02:00
|
|
|
return UpdateTitleSeekpoint( p_input,
|
2016-06-07 11:15:16 +02:00
|
|
|
demux_GetTitle( p_demux ),
|
|
|
|
demux_GetSeekpoint( p_demux ) );
|
2004-06-22 21:29:57 +02:00
|
|
|
}
|
|
|
|
|
2008-12-01 22:53:25 +01:00
|
|
|
static void UpdateGenericFromDemux( input_thread_t *p_input )
|
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
demux_t *p_demux = input_priv(p_input)->master->p_demux;
|
2008-12-01 22:53:25 +01:00
|
|
|
|
2016-06-09 19:58:55 +02:00
|
|
|
if( demux_TestAndClearFlags( p_demux, INPUT_UPDATE_META ) )
|
2014-08-15 19:16:58 +02:00
|
|
|
InputUpdateMeta( p_input, p_demux );
|
2016-06-09 19:58:55 +02:00
|
|
|
|
2013-08-26 19:21:14 +02:00
|
|
|
{
|
|
|
|
double quality;
|
|
|
|
double strength;
|
|
|
|
|
|
|
|
if( !demux_Control( p_demux, DEMUX_GET_SIGNAL, &quality, &strength ) )
|
|
|
|
input_SendEventSignal( p_input, quality, strength );
|
|
|
|
}
|
2008-12-01 22:53:25 +01:00
|
|
|
}
|
|
|
|
|
2012-12-05 23:07:18 +01:00
|
|
|
static void UpdateTitleListfromDemux( input_thread_t *p_input )
|
|
|
|
{
|
2017-08-25 14:43:25 +02:00
|
|
|
input_thread_private_t *priv = input_priv(p_input);
|
|
|
|
input_source_t *in = priv->master;
|
2012-12-05 23:07:18 +01:00
|
|
|
|
|
|
|
/* Delete the preexisting titles */
|
2019-05-10 14:58:39 +02:00
|
|
|
bool had_titles = in->i_title > 0;
|
2019-12-04 18:32:54 +01:00
|
|
|
if( had_titles )
|
|
|
|
{
|
|
|
|
for( int i = 0; i < in->i_title; i++ )
|
|
|
|
vlc_input_title_Delete( in->title[i] );
|
|
|
|
}
|
2020-01-08 11:02:56 +01:00
|
|
|
TAB_CLEAN( in->i_title, in->title );
|
2012-12-05 23:07:18 +01:00
|
|
|
|
|
|
|
/* Get the new title list */
|
|
|
|
if( demux_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
|
|
|
|
&in->title, &in->i_title,
|
|
|
|
&in->i_title_offset, &in->i_seekpoint_offset ) )
|
|
|
|
TAB_INIT( in->i_title, in->title );
|
|
|
|
else
|
|
|
|
in->b_title_demux = true;
|
|
|
|
|
2018-09-11 17:50:09 +02:00
|
|
|
InitTitle( p_input, had_titles );
|
2012-12-05 23:07:18 +01:00
|
|
|
}
|
|
|
|
|
2016-12-03 12:38:09 +01:00
|
|
|
static int
|
2018-10-17 09:31:35 +02:00
|
|
|
InputStreamHandleAnchor( input_thread_t *p_input, input_source_t *source,
|
|
|
|
stream_t **stream, char const *anchor )
|
2016-12-03 12:38:09 +01:00
|
|
|
{
|
|
|
|
char const* extra;
|
2017-03-17 03:22:32 +01:00
|
|
|
if( stream_extractor_AttachParsed( stream, anchor, &extra ) )
|
2016-12-03 12:38:09 +01:00
|
|
|
{
|
2018-10-17 09:31:35 +02:00
|
|
|
msg_Err( p_input, "unable to attach stream-extractors for %s",
|
2017-05-18 12:19:41 +02:00
|
|
|
(*stream)->psz_url );
|
|
|
|
|
2017-03-17 03:22:32 +01:00
|
|
|
return VLC_EGENERIC;
|
2016-12-03 12:38:09 +01:00
|
|
|
}
|
|
|
|
|
2017-03-17 03:22:32 +01:00
|
|
|
if( vlc_stream_directory_Attach( stream, NULL ) )
|
2018-10-17 09:31:35 +02:00
|
|
|
msg_Dbg( p_input, "attachment of directory-extractor failed for %s",
|
2017-05-18 12:19:41 +02:00
|
|
|
(*stream)->psz_url );
|
2017-03-17 03:22:32 +01:00
|
|
|
|
2016-12-03 12:38:09 +01:00
|
|
|
MRLSections( extra ? extra : "",
|
|
|
|
&source->i_title_start, &source->i_title_end,
|
|
|
|
&source->i_seekpoint_start, &source->i_seekpoint_end );
|
|
|
|
|
2017-03-17 03:22:32 +01:00
|
|
|
return VLC_SUCCESS;
|
2016-12-03 12:38:09 +01:00
|
|
|
}
|
|
|
|
|
2020-02-11 14:12:56 +01:00
|
|
|
static demux_t *InputDemuxNew( input_thread_t *p_input, es_out_t *p_es_out,
|
2018-04-16 16:49:01 +02:00
|
|
|
input_source_t *p_source, const char *url,
|
|
|
|
const char *psz_demux, const char *psz_anchor )
|
2016-12-03 12:43:00 +01:00
|
|
|
{
|
2016-12-03 12:46:28 +01:00
|
|
|
input_thread_private_t *priv = input_priv(p_input );
|
2018-10-17 09:31:35 +02:00
|
|
|
vlc_object_t *obj = VLC_OBJECT(p_input);
|
2016-12-03 12:43:00 +01:00
|
|
|
|
2018-04-16 16:49:01 +02:00
|
|
|
/* create the underlying access stream */
|
2020-02-11 14:12:56 +01:00
|
|
|
stream_t *p_stream = stream_AccessNew( obj, p_input, p_es_out,
|
2019-06-26 13:35:06 +02:00
|
|
|
priv->type == INPUT_TYPE_PREPARSING,
|
|
|
|
url );
|
2016-12-03 12:46:28 +01:00
|
|
|
if( p_stream == NULL )
|
2018-03-24 11:12:27 +01:00
|
|
|
return NULL;
|
2016-12-03 12:43:00 +01:00
|
|
|
|
2018-04-16 16:22:25 +02:00
|
|
|
p_stream = stream_FilterAutoNew( p_stream );
|
|
|
|
|
2023-03-17 11:48:19 +01:00
|
|
|
if(( p_stream->ops != NULL && (p_stream->ops->stream.read == NULL &&
|
|
|
|
p_stream->ops->stream.block == NULL && p_stream->ops->stream.readdir == NULL))
|
|
|
|
|| ( p_stream->ops == NULL && (p_stream->pf_read == NULL && p_stream->pf_block == NULL &&
|
|
|
|
p_stream->pf_readdir == NULL)) )
|
2018-03-25 05:35:04 +02:00
|
|
|
{ /* Combined access/demux, no stream filtering */
|
2018-04-16 16:46:35 +02:00
|
|
|
MRLSections( psz_anchor,
|
|
|
|
&p_source->i_title_start, &p_source->i_title_end,
|
2018-03-25 05:35:04 +02:00
|
|
|
&p_source->i_seekpoint_start, &p_source->i_seekpoint_end );
|
2018-04-16 16:46:35 +02:00
|
|
|
return p_stream;
|
2018-03-25 05:35:04 +02:00
|
|
|
}
|
|
|
|
|
2016-12-03 12:46:28 +01:00
|
|
|
/* attach explicit stream filters to stream */
|
2018-10-17 09:31:35 +02:00
|
|
|
char *psz_filters = var_InheritString( p_input, "stream-filter" );
|
2016-12-03 12:46:28 +01:00
|
|
|
if( psz_filters )
|
2018-03-24 11:12:27 +01:00
|
|
|
{
|
2016-12-03 12:46:28 +01:00
|
|
|
p_stream = stream_FilterChainNew( p_stream, psz_filters );
|
2018-03-24 11:12:27 +01:00
|
|
|
free( psz_filters );
|
|
|
|
}
|
2016-12-03 12:43:00 +01:00
|
|
|
|
2016-12-03 12:46:28 +01:00
|
|
|
/* handle anchors */
|
2018-10-17 09:31:35 +02:00
|
|
|
if( InputStreamHandleAnchor( p_input, p_source, &p_stream, psz_anchor ) )
|
2017-02-20 14:53:27 +01:00
|
|
|
goto error;
|
2016-12-03 12:46:28 +01:00
|
|
|
|
|
|
|
/* attach conditional record stream-filter */
|
2018-10-17 09:31:35 +02:00
|
|
|
if( var_InheritBool( p_input, "input-record-native" ) )
|
2016-12-03 12:46:28 +01:00
|
|
|
p_stream = stream_FilterChainNew( p_stream, "record" );
|
|
|
|
|
|
|
|
/* create a regular demux with the access stream created */
|
2018-04-16 16:49:01 +02:00
|
|
|
demux_t *demux = demux_NewAdvanced( obj, p_input, psz_demux, url, p_stream,
|
2019-06-26 13:35:06 +02:00
|
|
|
p_es_out, priv->type == INPUT_TYPE_PREPARSING );
|
2018-04-16 16:49:01 +02:00
|
|
|
if( demux != NULL )
|
|
|
|
return demux;
|
2016-12-03 12:46:28 +01:00
|
|
|
|
|
|
|
error:
|
2018-03-24 11:12:27 +01:00
|
|
|
vlc_stream_Delete( p_stream );
|
2016-12-03 12:46:28 +01:00
|
|
|
return NULL;
|
2016-12-03 12:43:00 +01:00
|
|
|
}
|
2008-12-01 22:53:25 +01:00
|
|
|
|
2018-04-16 16:52:33 +02:00
|
|
|
static void input_SplitMRL( const char **, const char **, const char **,
|
|
|
|
const char **, char * );
|
|
|
|
|
2020-02-26 13:09:26 +01:00
|
|
|
static input_source_t *InputSourceNew( const char *psz_mrl )
|
2004-06-25 00:21:36 +02:00
|
|
|
{
|
2018-10-17 09:31:35 +02:00
|
|
|
input_source_t *in = calloc(1, sizeof(*in) );
|
2015-10-24 19:57:33 +02:00
|
|
|
if( unlikely(in == NULL) )
|
|
|
|
return NULL;
|
2004-06-25 00:21:36 +02:00
|
|
|
|
2020-02-26 14:43:13 +01:00
|
|
|
vlc_atomic_rc_init( &in->rc );
|
2020-02-26 13:09:26 +01:00
|
|
|
|
|
|
|
if( psz_mrl )
|
|
|
|
{
|
|
|
|
/* Use the MD5 sum of the complete source URL as an identifier. */
|
2020-04-01 16:15:39 +02:00
|
|
|
vlc_hash_md5_t md5;
|
|
|
|
|
|
|
|
in->str_id = malloc(VLC_HASH_MD5_DIGEST_HEX_SIZE);
|
2020-02-26 13:09:26 +01:00
|
|
|
if( !in->str_id )
|
|
|
|
{
|
|
|
|
free( in );
|
|
|
|
return NULL;
|
|
|
|
}
|
2020-04-01 16:15:39 +02:00
|
|
|
|
|
|
|
vlc_hash_md5_Init( &md5 );
|
|
|
|
vlc_hash_md5_Update( &md5, psz_mrl, strlen( psz_mrl ) );
|
|
|
|
vlc_hash_FinishHex( &md5, in->str_id );
|
2020-02-26 13:09:26 +01:00
|
|
|
}
|
|
|
|
|
2020-02-26 14:43:13 +01:00
|
|
|
return in;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int InputSourceInit( input_source_t *in, input_thread_t *p_input,
|
|
|
|
const char *psz_mrl,
|
|
|
|
const char *psz_forced_demux, bool b_in_can_fail )
|
|
|
|
{
|
|
|
|
input_thread_private_t *priv = input_priv(p_input);
|
2012-08-31 02:37:15 +02:00
|
|
|
const char *psz_access, *psz_demux, *psz_path, *psz_anchor = NULL;
|
2020-02-26 15:15:06 +01:00
|
|
|
const bool master = priv->master == in;
|
2004-06-25 00:21:36 +02:00
|
|
|
|
2009-06-25 17:54:16 +02:00
|
|
|
assert( psz_mrl );
|
2009-03-17 18:58:49 +01:00
|
|
|
char *psz_dup = strdup( psz_mrl );
|
2016-12-03 12:58:22 +01:00
|
|
|
char *psz_demux_var = NULL;
|
2009-03-17 18:58:49 +01:00
|
|
|
|
|
|
|
if( psz_dup == NULL )
|
2020-02-26 14:43:13 +01:00
|
|
|
return VLC_ENOMEM;
|
2020-02-21 16:39:56 +01:00
|
|
|
|
2004-06-25 00:21:36 +02:00
|
|
|
/* Split uri */
|
2011-09-25 15:56:18 +02:00
|
|
|
input_SplitMRL( &psz_access, &psz_demux, &psz_path, &psz_anchor, psz_dup );
|
2008-03-04 21:10:06 +01:00
|
|
|
|
2016-12-03 12:58:22 +01:00
|
|
|
if( psz_demux == NULL || psz_demux[0] == '\0' )
|
2018-10-17 09:31:35 +02:00
|
|
|
psz_demux = psz_demux_var = var_InheritString( p_input, "demux" );
|
2016-12-03 12:58:22 +01:00
|
|
|
|
2015-10-21 18:47:58 +02:00
|
|
|
if( psz_forced_demux != NULL )
|
|
|
|
psz_demux = psz_forced_demux;
|
|
|
|
|
2016-12-03 12:58:22 +01:00
|
|
|
if( psz_demux == NULL )
|
|
|
|
psz_demux = "any";
|
|
|
|
|
2008-03-04 21:10:06 +01:00
|
|
|
msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'",
|
|
|
|
psz_mrl, psz_access, psz_demux, psz_path );
|
2015-07-22 22:13:19 +02:00
|
|
|
|
2016-11-05 09:11:44 +01:00
|
|
|
if( input_priv(p_input)->master == NULL /* XXX ugly */)
|
2015-10-21 18:47:58 +02:00
|
|
|
{ /* On master stream only, use input-list */
|
|
|
|
char *str = var_InheritString( p_input, "input-list" );
|
|
|
|
if( str != NULL )
|
|
|
|
{
|
|
|
|
char *list;
|
2015-07-22 22:13:19 +02:00
|
|
|
|
2015-10-21 18:47:58 +02:00
|
|
|
var_Create( p_input, "concat-list", VLC_VAR_STRING );
|
|
|
|
if( likely(asprintf( &list, "%s://%s,%s", psz_access, psz_path,
|
|
|
|
str ) >= 0) )
|
2015-07-22 22:13:19 +02:00
|
|
|
{
|
2015-10-21 18:47:58 +02:00
|
|
|
var_SetString( p_input, "concat-list", list );
|
|
|
|
free( list );
|
2015-07-22 22:13:19 +02:00
|
|
|
}
|
2015-10-21 18:47:58 +02:00
|
|
|
free( str );
|
|
|
|
psz_access = "concat";
|
2004-06-25 00:21:36 +02:00
|
|
|
}
|
2015-10-21 18:47:58 +02:00
|
|
|
}
|
2004-06-25 00:21:36 +02:00
|
|
|
|
2015-10-21 18:47:58 +02:00
|
|
|
if( strcasecmp( psz_access, "concat" ) )
|
|
|
|
{ /* Autodetect extra files if none specified */
|
|
|
|
int count;
|
|
|
|
char **tab;
|
2015-08-25 19:24:51 +02:00
|
|
|
|
2015-10-21 18:47:58 +02:00
|
|
|
TAB_INIT( count, tab );
|
2021-09-15 17:37:28 +02:00
|
|
|
InputGetExtraFiles( p_input, &count, &tab, &psz_access, psz_mrl );
|
2015-10-21 18:47:58 +02:00
|
|
|
if( count > 0 )
|
2015-08-25 19:51:47 +02:00
|
|
|
{
|
2015-10-21 18:47:58 +02:00
|
|
|
char *list = NULL;
|
2008-12-09 21:06:12 +01:00
|
|
|
|
2015-10-21 18:47:58 +02:00
|
|
|
for( int i = 0; i < count; i++ )
|
|
|
|
{
|
|
|
|
char *str;
|
|
|
|
if( asprintf( &str, "%s,%s", list ? list : psz_mrl,
|
|
|
|
tab[i] ) < 0 )
|
|
|
|
break;
|
2015-07-26 12:47:54 +02:00
|
|
|
|
2015-10-21 18:47:58 +02:00
|
|
|
free( tab[i] );
|
|
|
|
free( list );
|
|
|
|
list = str;
|
|
|
|
}
|
2007-05-18 15:56:22 +02:00
|
|
|
|
2015-10-21 18:47:58 +02:00
|
|
|
var_Create( p_input, "concat-list", VLC_VAR_STRING );
|
|
|
|
if( likely(list != NULL) )
|
|
|
|
{
|
|
|
|
var_SetString( p_input, "concat-list", list );
|
|
|
|
free( list );
|
|
|
|
}
|
2004-06-25 00:21:36 +02:00
|
|
|
}
|
2015-10-21 18:47:58 +02:00
|
|
|
TAB_CLEAN( count, tab );
|
2007-10-01 01:17:19 +02:00
|
|
|
}
|
|
|
|
|
2018-04-16 16:49:01 +02:00
|
|
|
char *url;
|
|
|
|
if( likely(asprintf( &url, "%s://%s", psz_access, psz_path ) >= 0) )
|
|
|
|
{
|
2020-02-26 15:15:06 +01:00
|
|
|
es_out_t *es_out;
|
|
|
|
if (!master )
|
|
|
|
es_out = in->p_slave_es_out =
|
|
|
|
input_EsOutSourceNew( priv->p_es_out, in );
|
|
|
|
else
|
|
|
|
es_out = priv->p_es_out;
|
|
|
|
|
|
|
|
if( es_out )
|
|
|
|
in->p_demux = InputDemuxNew( p_input, es_out, in, url,
|
|
|
|
psz_demux, psz_anchor );
|
2018-04-16 16:49:01 +02:00
|
|
|
free( url );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
in->p_demux = NULL;
|
2016-12-03 12:46:28 +01:00
|
|
|
|
2016-12-03 12:58:22 +01:00
|
|
|
free( psz_demux_var );
|
2009-03-17 18:58:49 +01:00
|
|
|
free( psz_dup );
|
|
|
|
|
2015-10-21 18:47:58 +02:00
|
|
|
if( in->p_demux == NULL )
|
|
|
|
{
|
|
|
|
if( !b_in_can_fail && !input_Stopped( p_input ) )
|
2023-03-16 10:03:01 +01:00
|
|
|
vlc_dialog_display_error( p_input, _("Your media can't be opened"),
|
2016-02-04 13:25:59 +01:00
|
|
|
_("VLC is unable to open the MRL '%s'."
|
|
|
|
" Check the log for details."), psz_mrl );
|
2020-02-26 15:15:06 +01:00
|
|
|
if( in->p_slave_es_out )
|
|
|
|
{
|
|
|
|
es_out_Delete( in->p_slave_es_out );
|
|
|
|
in->p_slave_es_out = NULL;
|
|
|
|
}
|
2020-02-26 14:43:13 +01:00
|
|
|
return VLC_EGENERIC;
|
2015-10-21 18:47:58 +02:00
|
|
|
}
|
|
|
|
|
2017-07-19 10:55:14 +02:00
|
|
|
char *psz_demux_chain = NULL;
|
|
|
|
if( priv->p_renderer )
|
|
|
|
{
|
|
|
|
const char* psz_renderer_demux = vlc_renderer_item_demux_filter(
|
|
|
|
priv->p_renderer );
|
|
|
|
if( psz_renderer_demux )
|
|
|
|
psz_demux_chain = strdup( psz_renderer_demux );
|
|
|
|
}
|
|
|
|
if( !psz_demux_chain )
|
|
|
|
psz_demux_chain = var_GetNonEmptyString(p_input, "demux-filter");
|
2017-07-08 15:49:31 +02:00
|
|
|
if( psz_demux_chain != NULL ) /* add the chain of demux filters */
|
|
|
|
{
|
|
|
|
in->p_demux = demux_FilterChainNew( in->p_demux, psz_demux_chain );
|
|
|
|
free( psz_demux_chain );
|
|
|
|
|
|
|
|
if( in->p_demux == NULL )
|
|
|
|
{
|
|
|
|
msg_Err(p_input, "Failed to create demux filter");
|
2020-02-26 15:15:06 +01:00
|
|
|
if( in->p_slave_es_out )
|
|
|
|
{
|
|
|
|
es_out_Delete( in->p_slave_es_out );
|
|
|
|
in->p_slave_es_out = NULL;
|
|
|
|
}
|
2020-02-26 14:43:13 +01:00
|
|
|
return VLC_EGENERIC;
|
2017-07-08 15:49:31 +02:00
|
|
|
}
|
|
|
|
}
|
2016-06-12 08:22:00 +02:00
|
|
|
|
2015-10-20 20:42:46 +02:00
|
|
|
/* Get infos from (access_)demux */
|
|
|
|
if( demux_Control( in->p_demux, DEMUX_CAN_CONTROL_PACE,
|
|
|
|
&in->b_can_pace_control ) )
|
|
|
|
in->b_can_pace_control = false;
|
|
|
|
|
2023-03-17 11:48:19 +01:00
|
|
|
const bool b_can_demux = in->p_demux->ops != NULL ?
|
|
|
|
in->p_demux->ops->demux.demux != NULL : in->p_demux->pf_demux != NULL;
|
|
|
|
|
2020-09-27 11:13:58 +02:00
|
|
|
/* Threaded and directory demuxers do not have pace control */
|
2023-03-17 11:48:19 +01:00
|
|
|
assert( b_can_demux || !in->b_can_pace_control );
|
2015-10-20 20:42:46 +02:00
|
|
|
|
2016-06-16 23:15:24 +02:00
|
|
|
if( !in->b_can_pace_control )
|
2015-10-20 20:42:46 +02:00
|
|
|
{
|
2016-06-16 23:15:24 +02:00
|
|
|
if( demux_Control( in->p_demux, DEMUX_CAN_CONTROL_RATE,
|
|
|
|
&in->b_can_rate_control ) )
|
2015-10-20 20:42:46 +02:00
|
|
|
{
|
2016-06-16 23:15:24 +02:00
|
|
|
in->b_can_rate_control = false;
|
2015-10-20 20:42:46 +02:00
|
|
|
in->b_rescale_ts = true;
|
|
|
|
}
|
2016-06-16 23:15:24 +02:00
|
|
|
else
|
|
|
|
in->b_rescale_ts = !in->b_can_rate_control;
|
2015-10-20 20:42:46 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-06-16 23:15:24 +02:00
|
|
|
in->b_can_rate_control = true;
|
2015-10-20 20:42:46 +02:00
|
|
|
in->b_rescale_ts = true;
|
|
|
|
}
|
|
|
|
|
2008-08-28 11:27:21 +02:00
|
|
|
/* Set record capabilities */
|
|
|
|
if( demux_Control( in->p_demux, DEMUX_CAN_RECORD, &in->b_can_stream_record ) )
|
|
|
|
in->b_can_stream_record = false;
|
|
|
|
#ifdef ENABLE_SOUT
|
2008-12-08 22:34:33 +01:00
|
|
|
if( !var_GetBool( p_input, "input-record-native" ) )
|
2008-08-28 11:27:21 +02:00
|
|
|
in->b_can_stream_record = false;
|
|
|
|
#endif
|
|
|
|
|
2021-04-27 13:46:29 +02:00
|
|
|
demux_Control( in->p_demux, DEMUX_CAN_PAUSE, &in->b_can_pause );
|
core: first cleaning of input_thread_t variables/event
Currently, the input_thread_t is controllable by either input_Control, specific
functions, by variables or by the 3 previous solutions.
The goal of this commit is to remove variables usage when it's not necessary.
This commit doesn't remove variables that should be used to pass users settings
(cf. input_ConfigVarInit).
The "intf-event" callback is replaced by the new callback
input_thread_events_cb that pass a new event: struct vlc_input_event. There can
be only one listener: the creator of the input_thread_t. In the future, the new
vlc input controller will receive these events and forward them to all
listeners.
In the meantime, I added input_LegacyVarInit, input_LegacyVarStop, and
input_LegacyEvents, 3 helpers functions that reproduce the legacy variable
behavior (transform new vlc_input_event to old intf-event events). These 3
functions are meant to be removed for 4.0 release (when vlc input controller is
added).
For now, the playlist, the media_player, VLM and modules still use the legacy
variables.
2018-07-06 13:43:55 +02:00
|
|
|
|
2007-10-01 01:17:19 +02:00
|
|
|
/* get attachment
|
2019-06-26 13:35:06 +02:00
|
|
|
* FIXME improve for preparsing: move it after GET_META and check psz_arturl */
|
|
|
|
if( input_priv(p_input)->type != INPUT_TYPE_PREPARSING )
|
2007-10-01 01:17:19 +02:00
|
|
|
{
|
2015-10-20 20:42:46 +02:00
|
|
|
if( demux_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
|
|
|
|
&in->title, &in->i_title,
|
|
|
|
&in->i_title_offset, &in->i_seekpoint_offset ))
|
|
|
|
{
|
|
|
|
TAB_INIT( in->i_title, in->title );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
in->b_title_demux = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
demux_Control( in->p_demux, DEMUX_GET_PTS_DELAY, &in->i_pts_delay );
|
2010-11-17 22:40:36 +01:00
|
|
|
if( in->i_pts_delay > INPUT_PTS_DELAY_MAX )
|
|
|
|
in->i_pts_delay = INPUT_PTS_DELAY_MAX;
|
|
|
|
else if( in->i_pts_delay < 0 )
|
|
|
|
in->i_pts_delay = 0;
|
2004-06-25 00:21:36 +02:00
|
|
|
}
|
2010-11-17 22:40:36 +01:00
|
|
|
|
2015-10-24 20:32:29 +02:00
|
|
|
if( demux_Control( in->p_demux, DEMUX_GET_FPS, &in->f_fps ) )
|
|
|
|
in->f_fps = 0.f;
|
2005-02-10 14:26:52 +01:00
|
|
|
|
|
|
|
if( var_GetInteger( p_input, "clock-synchro" ) != -1 )
|
|
|
|
in->b_can_pace_control = !var_GetInteger( p_input, "clock-synchro" );
|
|
|
|
|
2020-02-26 14:43:13 +01:00
|
|
|
return VLC_SUCCESS;
|
2004-06-25 00:21:36 +02:00
|
|
|
}
|
|
|
|
|
2020-02-21 16:39:56 +01:00
|
|
|
input_source_t *input_source_Hold( input_source_t *in )
|
|
|
|
{
|
|
|
|
vlc_atomic_rc_inc( &in->rc );
|
|
|
|
return in;
|
|
|
|
}
|
|
|
|
|
|
|
|
void input_source_Release( input_source_t *in )
|
|
|
|
{
|
|
|
|
if( vlc_atomic_rc_dec( &in->rc ) )
|
2020-02-26 13:09:26 +01:00
|
|
|
{
|
|
|
|
free( in->str_id );
|
2020-02-21 16:39:56 +01:00
|
|
|
free( in );
|
2020-02-26 13:09:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *input_source_GetStrId( input_source_t *in )
|
|
|
|
{
|
|
|
|
return in->str_id;
|
2020-02-21 16:39:56 +01:00
|
|
|
}
|
|
|
|
|
2020-02-26 15:15:03 +01:00
|
|
|
int input_source_GetNewAutoId( input_source_t *in )
|
|
|
|
{
|
|
|
|
return in->auto_id++;
|
|
|
|
}
|
|
|
|
|
2021-04-22 14:11:31 +02:00
|
|
|
bool input_source_IsAutoSelected( input_source_t *in )
|
2020-02-28 14:07:14 +01:00
|
|
|
{
|
2021-04-22 14:11:31 +02:00
|
|
|
return in->autoselected;
|
2020-02-28 14:07:14 +01:00
|
|
|
}
|
|
|
|
|
2004-06-25 00:21:36 +02:00
|
|
|
/*****************************************************************************
|
2015-10-24 19:57:33 +02:00
|
|
|
* InputSourceDestroy:
|
2004-06-25 00:21:36 +02:00
|
|
|
*****************************************************************************/
|
2015-10-24 19:57:33 +02:00
|
|
|
static void InputSourceDestroy( input_source_t *in )
|
2004-06-25 00:21:36 +02:00
|
|
|
{
|
2007-05-31 21:22:27 +02:00
|
|
|
int i;
|
|
|
|
|
2004-06-25 00:21:36 +02:00
|
|
|
if( in->p_demux )
|
2008-04-14 00:20:09 +02:00
|
|
|
demux_Delete( in->p_demux );
|
2020-02-26 15:15:06 +01:00
|
|
|
if( in->p_slave_es_out )
|
|
|
|
es_out_Delete( in->p_slave_es_out );
|
2004-06-25 00:21:36 +02:00
|
|
|
|
|
|
|
if( in->i_title > 0 )
|
|
|
|
{
|
|
|
|
for( i = 0; i < in->i_title; i++ )
|
|
|
|
vlc_input_title_Delete( in->title[i] );
|
|
|
|
}
|
2020-01-08 11:02:56 +01:00
|
|
|
TAB_CLEAN( in->i_title, in->title );
|
2004-06-25 00:21:36 +02:00
|
|
|
}
|
|
|
|
|
2008-12-01 23:52:02 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* InputSourceMeta:
|
|
|
|
*****************************************************************************/
|
|
|
|
static void InputSourceMeta( input_thread_t *p_input,
|
|
|
|
input_source_t *p_source, vlc_meta_t *p_meta )
|
|
|
|
{
|
|
|
|
demux_t *p_demux = p_source->p_demux;
|
|
|
|
|
|
|
|
/* XXX Remember that checking against p_item->p_meta->i_status & ITEM_PREPARSED
|
|
|
|
* is a bad idea */
|
|
|
|
|
2013-04-17 22:53:52 +02:00
|
|
|
bool has_meta = false;
|
2010-01-07 01:02:10 +01:00
|
|
|
|
2008-12-01 23:52:02 +01:00
|
|
|
/* Read demux meta */
|
2013-04-17 22:53:52 +02:00
|
|
|
if( !demux_Control( p_demux, DEMUX_GET_META, p_meta ) )
|
|
|
|
has_meta = true;
|
2008-12-01 23:52:02 +01:00
|
|
|
|
2010-01-07 01:02:10 +01:00
|
|
|
bool has_unsupported;
|
|
|
|
if( demux_Control( p_demux, DEMUX_HAS_UNSUPPORTED_META, &has_unsupported ) )
|
|
|
|
has_unsupported = true;
|
|
|
|
|
|
|
|
/* If the demux report unsupported meta data, or if we don't have meta data
|
|
|
|
* try an external "meta reader" */
|
|
|
|
if( has_meta && !has_unsupported )
|
2008-12-01 23:52:02 +01:00
|
|
|
return;
|
|
|
|
|
2009-08-23 18:20:44 +02:00
|
|
|
demux_meta_t *p_demux_meta =
|
2018-10-17 09:31:35 +02:00
|
|
|
vlc_custom_create( p_input, sizeof( *p_demux_meta ), "demux meta" );
|
2015-08-05 17:59:58 +02:00
|
|
|
if( unlikely(p_demux_meta == NULL) )
|
2008-12-01 23:52:02 +01:00
|
|
|
return;
|
2016-11-05 09:11:44 +01:00
|
|
|
p_demux_meta->p_item = input_priv(p_input)->p_item;
|
2008-12-01 23:52:02 +01:00
|
|
|
|
2009-08-23 18:20:44 +02:00
|
|
|
module_t *p_id3 = module_need( p_demux_meta, "meta reader", NULL, false );
|
2008-12-01 23:52:02 +01:00
|
|
|
if( p_id3 )
|
|
|
|
{
|
|
|
|
if( p_demux_meta->p_meta )
|
|
|
|
{
|
|
|
|
vlc_meta_Merge( p_meta, p_demux_meta->p_meta );
|
|
|
|
vlc_meta_Delete( p_demux_meta->p_meta );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( p_demux_meta->i_attachments > 0 )
|
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
vlc_mutex_lock( &input_priv(p_input)->p_item->lock );
|
2020-11-04 10:24:25 +01:00
|
|
|
AppendAttachment( p_input, p_demux_meta->i_attachments,
|
2020-11-04 13:26:19 +01:00
|
|
|
p_demux_meta->attachments );
|
2016-11-05 09:11:44 +01:00
|
|
|
vlc_mutex_unlock( &input_priv(p_input)->p_item->lock );
|
2008-12-01 23:52:02 +01:00
|
|
|
}
|
2021-09-05 05:30:39 +02:00
|
|
|
module_unneed( p_demux_meta, p_id3 );
|
2008-12-01 23:52:02 +01:00
|
|
|
}
|
2019-03-06 19:15:18 +01:00
|
|
|
vlc_object_delete(p_demux_meta);
|
2008-12-01 23:52:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-21 18:21:39 +01:00
|
|
|
static void SlaveDemux( input_thread_t *p_input )
|
2004-06-25 00:21:36 +02:00
|
|
|
{
|
2018-10-17 14:43:14 +02:00
|
|
|
input_thread_private_t *priv = input_priv(p_input);
|
2018-05-05 15:28:18 +02:00
|
|
|
vlc_tick_t i_time;
|
2004-06-25 00:21:36 +02:00
|
|
|
int i;
|
2006-10-29 10:38:43 +01:00
|
|
|
|
2018-02-23 17:54:41 +01:00
|
|
|
if( demux_Control( input_priv(p_input)->master->p_demux, DEMUX_GET_TIME, &i_time ) )
|
2004-06-25 00:21:36 +02:00
|
|
|
{
|
2009-01-03 22:14:57 +01:00
|
|
|
msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
|
|
|
|
return;
|
2004-06-25 00:21:36 +02:00
|
|
|
}
|
|
|
|
|
2016-11-05 09:11:44 +01:00
|
|
|
for( i = 0; i < input_priv(p_input)->i_slave; i++ )
|
2004-06-25 00:21:36 +02:00
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
input_source_t *in = input_priv(p_input)->slave[i];
|
2009-07-17 18:44:53 +02:00
|
|
|
int i_ret;
|
2004-06-25 00:21:36 +02:00
|
|
|
|
|
|
|
if( in->b_eof )
|
|
|
|
continue;
|
|
|
|
|
2019-02-15 15:38:39 +01:00
|
|
|
if( priv->slave_subs_rate != in->sub_rate )
|
2018-10-17 14:43:14 +02:00
|
|
|
{
|
|
|
|
if( in->b_slave_sub && in->b_can_rate_control )
|
|
|
|
{
|
2019-02-15 15:38:39 +01:00
|
|
|
if( in->sub_rate != 0 ) /* Don't reset when it's the first time */
|
2018-10-17 14:43:14 +02:00
|
|
|
es_out_Control( priv->p_es_out, ES_OUT_RESET_PCR );
|
2019-02-15 15:38:39 +01:00
|
|
|
float new_rate = priv->slave_subs_rate;
|
|
|
|
demux_Control( in->p_demux, DEMUX_SET_RATE, &new_rate );
|
2018-10-17 14:43:14 +02:00
|
|
|
}
|
2019-02-15 15:38:39 +01:00
|
|
|
in->sub_rate = priv->slave_subs_rate;
|
2018-10-17 14:43:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-07-17 18:45:13 +02:00
|
|
|
/* Call demux_Demux until we have read enough data */
|
2009-01-03 22:14:57 +01:00
|
|
|
if( demux_Control( in->p_demux, DEMUX_SET_NEXT_DEMUX_TIME, i_time ) )
|
2004-06-25 00:21:36 +02:00
|
|
|
{
|
|
|
|
for( ;; )
|
|
|
|
{
|
2018-05-05 15:28:18 +02:00
|
|
|
vlc_tick_t i_stime;
|
2008-04-14 00:20:09 +02:00
|
|
|
if( demux_Control( in->p_demux, DEMUX_GET_TIME, &i_stime ) )
|
2004-06-25 00:21:36 +02:00
|
|
|
{
|
2004-06-27 12:19:23 +02:00
|
|
|
msg_Err( p_input, "slave[%d] doesn't like "
|
|
|
|
"DEMUX_GET_TIME -> EOF", i );
|
2004-06-25 00:21:36 +02:00
|
|
|
i_ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
2004-06-29 00:49:43 +02:00
|
|
|
|
2004-06-25 00:21:36 +02:00
|
|
|
if( i_stime >= i_time )
|
2009-07-17 18:44:53 +02:00
|
|
|
{
|
|
|
|
i_ret = 1;
|
2004-06-25 00:21:36 +02:00
|
|
|
break;
|
2009-07-17 18:44:53 +02:00
|
|
|
}
|
2004-06-25 00:21:36 +02:00
|
|
|
|
2008-12-01 23:19:12 +01:00
|
|
|
if( ( i_ret = demux_Demux( in->p_demux ) ) <= 0 )
|
2004-06-25 00:21:36 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-12-01 23:19:12 +01:00
|
|
|
i_ret = demux_Demux( in->p_demux );
|
2004-06-25 00:21:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if( i_ret <= 0 )
|
|
|
|
{
|
|
|
|
msg_Dbg( p_input, "slave %d EOF", i );
|
2008-04-14 00:08:29 +02:00
|
|
|
in->b_eof = true;
|
2004-06-25 00:21:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void SlaveSeek( input_thread_t *p_input )
|
|
|
|
{
|
2018-05-05 15:28:18 +02:00
|
|
|
vlc_tick_t i_time;
|
2004-06-25 00:21:36 +02:00
|
|
|
int i;
|
|
|
|
|
2016-11-05 09:11:44 +01:00
|
|
|
if( demux_Control( input_priv(p_input)->master->p_demux, DEMUX_GET_TIME, &i_time ) )
|
2004-06-25 00:21:36 +02:00
|
|
|
{
|
|
|
|
msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-11-05 09:11:44 +01:00
|
|
|
for( i = 0; i < input_priv(p_input)->i_slave; i++ )
|
2004-06-25 00:21:36 +02:00
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
input_source_t *in = input_priv(p_input)->slave[i];
|
2004-06-25 00:21:36 +02:00
|
|
|
|
2009-01-24 12:14:10 +01:00
|
|
|
if( demux_Control( in->p_demux, DEMUX_SET_TIME, i_time, true ) )
|
2004-06-25 00:21:36 +02:00
|
|
|
{
|
2008-09-18 20:15:29 +02:00
|
|
|
if( !in->b_eof )
|
|
|
|
msg_Err( p_input, "seek failed for slave %d -> EOF", i );
|
2008-04-14 00:08:29 +02:00
|
|
|
in->b_eof = true;
|
2004-06-25 00:21:36 +02:00
|
|
|
}
|
2008-09-18 00:01:01 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
in->b_eof = false;
|
|
|
|
}
|
2004-06-25 00:21:36 +02:00
|
|
|
}
|
|
|
|
}
|
2006-10-29 14:37:30 +01:00
|
|
|
|
2004-06-29 00:49:43 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* InputMetaUser:
|
|
|
|
*****************************************************************************/
|
2007-06-04 00:40:17 +02:00
|
|
|
static void InputMetaUser( input_thread_t *p_input, vlc_meta_t *p_meta )
|
2004-06-29 00:49:43 +02:00
|
|
|
{
|
2009-03-27 22:46:07 +01:00
|
|
|
static const struct { int i_meta; const char *psz_name; } p_list[] = {
|
|
|
|
{ vlc_meta_Title, "meta-title" },
|
|
|
|
{ vlc_meta_Artist, "meta-artist" },
|
|
|
|
{ vlc_meta_Genre, "meta-genre" },
|
|
|
|
{ vlc_meta_Copyright, "meta-copyright" },
|
|
|
|
{ vlc_meta_Description, "meta-description" },
|
|
|
|
{ vlc_meta_Date, "meta-date" },
|
|
|
|
{ vlc_meta_URL, "meta-url" },
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
2004-06-29 00:49:43 +02:00
|
|
|
/* Get meta information from user */
|
2009-03-27 22:46:07 +01:00
|
|
|
for( int i = 0; p_list[i].psz_name; i++ )
|
|
|
|
{
|
|
|
|
char *psz_string = var_GetNonEmptyString( p_input, p_list[i].psz_name );
|
|
|
|
if( !psz_string )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
EnsureUTF8( psz_string );
|
|
|
|
vlc_meta_Set( p_meta, p_list[i].i_meta, psz_string );
|
|
|
|
free( psz_string );
|
|
|
|
}
|
2004-06-29 00:49:43 +02:00
|
|
|
}
|
2004-06-25 00:21:36 +02:00
|
|
|
|
2020-11-04 10:24:25 +01:00
|
|
|
static void AppendAttachment( input_thread_t *p_input, int i_new,
|
2020-11-04 13:26:19 +01:00
|
|
|
input_attachment_t **pp_new )
|
2007-10-08 20:30:11 +02:00
|
|
|
{
|
2020-11-04 10:24:25 +01:00
|
|
|
input_thread_private_t *priv = input_priv( p_input );
|
|
|
|
int i_attachment = priv->i_attachment;
|
2007-10-08 20:30:11 +02:00
|
|
|
int i;
|
|
|
|
|
2019-12-12 19:42:04 +01:00
|
|
|
if ( i_attachment + i_new == 0 )
|
2020-11-25 16:55:28 +01:00
|
|
|
{
|
|
|
|
free( pp_new );
|
2019-12-12 19:42:04 +01:00
|
|
|
return;
|
2020-11-25 16:55:28 +01:00
|
|
|
}
|
2019-12-12 19:42:04 +01:00
|
|
|
|
2020-11-04 10:24:25 +01:00
|
|
|
input_attachment_t **pp_att = realloc( priv->attachment,
|
2016-07-19 21:29:43 +02:00
|
|
|
sizeof(*pp_att) * ( i_attachment + i_new ) );
|
|
|
|
if( likely(pp_att) )
|
2014-09-20 19:16:33 +02:00
|
|
|
{
|
2020-11-04 10:24:25 +01:00
|
|
|
priv->attachment = pp_att;
|
2020-11-04 13:26:19 +01:00
|
|
|
for( i = 0; i < i_new; i++ )
|
2016-07-19 21:29:43 +02:00
|
|
|
{
|
2020-11-04 13:26:19 +01:00
|
|
|
pp_att[i_attachment++] = pp_new[i];
|
2016-07-19 21:29:43 +02:00
|
|
|
}
|
2020-11-04 13:26:19 +01:00
|
|
|
/* */
|
|
|
|
priv->i_attachment = i_attachment;
|
2020-11-18 14:54:28 +01:00
|
|
|
vlc_event_send( &priv->p_item->event_manager, &(vlc_event_t) {
|
|
|
|
.type = vlc_InputItemAttachmentsFound,
|
|
|
|
.u.input_item_attachments_found.attachments = pp_new,
|
|
|
|
.u.input_item_attachments_found.count = i_new } );
|
2020-11-04 13:26:19 +01:00
|
|
|
free( pp_new );
|
|
|
|
return;
|
2014-09-20 19:16:33 +02:00
|
|
|
}
|
2007-10-08 20:30:11 +02:00
|
|
|
|
2016-07-19 21:29:43 +02:00
|
|
|
/* on alloc errors */
|
|
|
|
for( i = 0; i < i_new; i++ )
|
2020-10-27 17:14:28 +01:00
|
|
|
vlc_input_attachment_Release( pp_new[i] );
|
2016-07-19 21:29:43 +02:00
|
|
|
free( pp_new );
|
2007-10-08 20:30:11 +02:00
|
|
|
}
|
2013-04-25 06:50:42 +02:00
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
* InputUpdateMeta: merge p_item meta data with p_meta taking care of
|
|
|
|
* arturl and locking issue.
|
|
|
|
*****************************************************************************/
|
2014-08-15 19:16:58 +02:00
|
|
|
static void InputUpdateMeta( input_thread_t *p_input, demux_t *p_demux )
|
2013-04-25 06:50:42 +02:00
|
|
|
{
|
2014-08-15 19:16:58 +02:00
|
|
|
vlc_meta_t *p_meta = vlc_meta_New();
|
|
|
|
if( unlikely(p_meta == NULL) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
demux_Control( p_demux, DEMUX_GET_META, p_meta );
|
|
|
|
|
2013-04-25 06:50:42 +02:00
|
|
|
/* If metadata changed, then the attachments might have changed.
|
|
|
|
We need to update them in case they contain album art. */
|
|
|
|
input_attachment_t **attachment;
|
2014-08-15 19:16:58 +02:00
|
|
|
int i_attachment;
|
|
|
|
|
|
|
|
if( !demux_Control( p_demux, DEMUX_GET_ATTACHMENTS,
|
|
|
|
&attachment, &i_attachment ) )
|
2013-04-25 06:50:42 +02:00
|
|
|
{
|
2020-11-04 13:23:53 +01:00
|
|
|
input_thread_private_t *priv = input_priv(p_input);
|
|
|
|
vlc_mutex_lock( &priv->p_item->lock );
|
|
|
|
int nb_new = 0;
|
|
|
|
for ( int i = 0; i < i_attachment; ++i )
|
2013-04-25 06:50:42 +02:00
|
|
|
{
|
2020-11-04 13:23:53 +01:00
|
|
|
bool is_new = true;
|
|
|
|
for( int j = 0; j < priv->i_attachment; ++j )
|
2014-09-20 19:16:33 +02:00
|
|
|
{
|
2020-11-04 13:23:53 +01:00
|
|
|
if( priv->attachment[j] == attachment[i] )
|
2014-09-20 19:16:33 +02:00
|
|
|
{
|
2020-11-04 13:23:53 +01:00
|
|
|
vlc_input_attachment_Release( attachment[i] );
|
|
|
|
is_new = false;
|
|
|
|
break;
|
2014-09-20 19:16:33 +02:00
|
|
|
}
|
|
|
|
}
|
2020-11-04 13:23:53 +01:00
|
|
|
if( is_new )
|
|
|
|
attachment[nb_new++] = attachment[i];
|
2013-04-25 06:50:42 +02:00
|
|
|
}
|
2020-11-04 13:26:19 +01:00
|
|
|
AppendAttachment( p_input, nb_new, attachment );
|
2020-11-04 13:23:53 +01:00
|
|
|
vlc_mutex_unlock( &priv->p_item->lock );
|
2013-04-25 06:50:42 +02:00
|
|
|
}
|
2014-08-15 19:16:58 +02:00
|
|
|
|
2016-11-05 09:11:44 +01:00
|
|
|
es_out_ControlSetMeta( input_priv(p_input)->p_es_out, p_meta );
|
2013-04-25 06:50:42 +02:00
|
|
|
vlc_meta_Delete( p_meta );
|
|
|
|
}
|
|
|
|
|
2008-12-01 23:16:39 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* InputGetExtraFiles
|
|
|
|
* Autodetect extra input list
|
|
|
|
*****************************************************************************/
|
2008-12-13 16:58:32 +01:00
|
|
|
static void InputGetExtraFilesPattern( input_thread_t *p_input,
|
|
|
|
int *pi_list, char ***pppsz_list,
|
2021-09-15 17:37:28 +02:00
|
|
|
const char *uri,
|
2008-12-13 16:58:32 +01:00
|
|
|
const char *psz_match,
|
|
|
|
const char *psz_format,
|
|
|
|
int i_start, int i_stop )
|
2008-12-01 23:16:39 +01:00
|
|
|
{
|
2008-12-13 01:17:58 +01:00
|
|
|
int i_list;
|
|
|
|
char **ppsz_list;
|
|
|
|
TAB_INIT( i_list, ppsz_list );
|
2008-12-01 23:16:39 +01:00
|
|
|
|
2008-12-13 16:58:32 +01:00
|
|
|
/* Remove the extension */
|
2021-09-15 17:53:30 +02:00
|
|
|
size_t end = strlen(uri) - strlen(psz_match);
|
|
|
|
if (unlikely(end > INT_MAX))
|
|
|
|
goto exit;
|
2008-12-01 23:16:39 +01:00
|
|
|
|
2008-12-13 16:58:32 +01:00
|
|
|
/* Try to list files */
|
|
|
|
for( int i = i_start; i <= i_stop; i++ )
|
2008-12-01 23:16:39 +01:00
|
|
|
{
|
2021-09-15 17:40:43 +02:00
|
|
|
char *url;
|
2021-09-15 17:53:30 +02:00
|
|
|
if( asprintf( &url, psz_format, (int)end, uri, i ) < 0 )
|
2021-09-15 17:37:28 +02:00
|
|
|
break;
|
2021-09-15 17:40:43 +02:00
|
|
|
|
|
|
|
char *filepath = vlc_uri2path(url);
|
2012-12-05 23:35:05 +01:00
|
|
|
|
2017-05-25 22:08:58 +02:00
|
|
|
struct stat st;
|
2017-06-29 22:32:39 +02:00
|
|
|
if( filepath == NULL ||
|
|
|
|
vlc_stat( filepath, &st ) || !S_ISREG( st.st_mode ) || !st.st_size )
|
2008-12-13 16:58:32 +01:00
|
|
|
{
|
2017-06-29 22:32:39 +02:00
|
|
|
free( filepath );
|
2021-09-15 17:40:43 +02:00
|
|
|
free( url );
|
2008-12-13 16:58:32 +01:00
|
|
|
break;
|
|
|
|
}
|
2008-12-01 23:16:39 +01:00
|
|
|
|
2017-06-29 22:32:39 +02:00
|
|
|
msg_Dbg( p_input, "Detected extra file `%s'", filepath );
|
|
|
|
free( filepath );
|
2021-09-15 17:40:43 +02:00
|
|
|
TAB_APPEND( i_list, ppsz_list, url );
|
2008-12-01 23:16:39 +01:00
|
|
|
}
|
2008-12-13 01:17:58 +01:00
|
|
|
exit:
|
|
|
|
*pi_list = i_list;
|
|
|
|
*pppsz_list = ppsz_list;
|
2008-12-01 23:16:39 +01:00
|
|
|
}
|
|
|
|
|
2008-12-13 16:58:32 +01:00
|
|
|
static void InputGetExtraFiles( input_thread_t *p_input,
|
|
|
|
int *pi_list, char ***pppsz_list,
|
2021-09-15 17:37:28 +02:00
|
|
|
const char **ppsz_access, const char *mrl )
|
2008-12-13 16:58:32 +01:00
|
|
|
{
|
2017-05-25 21:58:02 +02:00
|
|
|
static const struct pattern
|
2008-12-13 16:58:32 +01:00
|
|
|
{
|
2017-05-25 21:58:04 +02:00
|
|
|
const char *psz_access_force;
|
2008-12-13 16:58:32 +01:00
|
|
|
const char *psz_match;
|
|
|
|
const char *psz_format;
|
|
|
|
int i_start;
|
|
|
|
int i_stop;
|
2017-05-25 21:58:02 +02:00
|
|
|
} patterns[] = {
|
2008-12-13 16:58:32 +01:00
|
|
|
/* XXX the order is important */
|
2021-09-15 17:53:30 +02:00
|
|
|
{ "concat", ".001", "%.*s.%.3d", 2, 999 },
|
|
|
|
{ NULL, ".part1.rar","%.*s.part%.1d.rar", 2, 9 },
|
|
|
|
{ NULL, ".part01.rar","%.*s.part%.2d.rar", 2, 99, },
|
|
|
|
{ NULL, ".part001.rar", "%.*s.part%.3d.rar", 2, 999 },
|
|
|
|
{ NULL, ".rar", "%.*s.r%.2d", 0, 99 },
|
|
|
|
{ "concat", ".mts", "%.*s.mts%d", 1, 999 },
|
2008-12-13 16:58:32 +01:00
|
|
|
};
|
|
|
|
|
2021-09-15 17:37:28 +02:00
|
|
|
assert(mrl != NULL);
|
2008-12-13 16:58:32 +01:00
|
|
|
TAB_INIT( *pi_list, *pppsz_list );
|
|
|
|
|
2021-09-15 17:37:28 +02:00
|
|
|
if( **ppsz_access && strcmp( *ppsz_access, "file" ) )
|
2008-12-13 16:58:32 +01:00
|
|
|
return;
|
|
|
|
|
2021-09-15 17:37:28 +02:00
|
|
|
const size_t i_path = strlen(mrl);
|
2008-12-13 16:58:32 +01:00
|
|
|
|
2017-05-25 21:58:02 +02:00
|
|
|
for( size_t i = 0; i < ARRAY_SIZE( patterns ); ++i )
|
2008-12-13 16:58:32 +01:00
|
|
|
{
|
2017-05-25 21:58:02 +02:00
|
|
|
const struct pattern* pat = &patterns[i];
|
|
|
|
const size_t i_ext = strlen( pat->psz_match );
|
2008-12-13 16:58:32 +01:00
|
|
|
|
|
|
|
if( i_path < i_ext )
|
|
|
|
continue;
|
2017-05-25 21:58:02 +02:00
|
|
|
|
2021-09-15 17:37:28 +02:00
|
|
|
if( !strcmp( &mrl[i_path-i_ext], pat->psz_match ) )
|
2008-12-13 16:58:32 +01:00
|
|
|
{
|
2021-09-15 17:37:28 +02:00
|
|
|
InputGetExtraFilesPattern( p_input, pi_list, pppsz_list, mrl,
|
2017-05-25 21:58:02 +02:00
|
|
|
pat->psz_match, pat->psz_format, pat->i_start, pat->i_stop );
|
2017-05-25 21:58:04 +02:00
|
|
|
|
|
|
|
if( *pi_list > 0 && pat->psz_access_force )
|
|
|
|
*ppsz_access = pat->psz_access_force;
|
2008-12-13 16:58:32 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-12-01 23:16:39 +01:00
|
|
|
|
|
|
|
/* */
|
2019-08-13 17:57:39 +02:00
|
|
|
static void input_ChangeState( input_thread_t *p_input, int i_state,
|
|
|
|
vlc_tick_t state_date )
|
2008-11-20 21:49:51 +01:00
|
|
|
{
|
2016-11-05 09:11:44 +01:00
|
|
|
if( input_priv(p_input)->i_state == i_state )
|
2015-06-05 21:18:18 +02:00
|
|
|
return;
|
2008-11-20 21:49:51 +01:00
|
|
|
|
2016-11-05 09:11:44 +01:00
|
|
|
input_priv(p_input)->i_state = i_state;
|
2008-11-20 21:49:51 +01:00
|
|
|
if( i_state == ERROR_S )
|
2016-11-05 09:11:44 +01:00
|
|
|
input_item_SetErrorWhenReading( input_priv(p_input)->p_item, true );
|
2022-09-14 21:07:37 +02:00
|
|
|
if (i_state == END_S || i_state == ERROR_S)
|
|
|
|
input_SendEventCapabilities( p_input, 0 );
|
2019-08-13 17:57:39 +02:00
|
|
|
input_SendEventState( p_input, i_state, state_date );
|
2008-11-20 21:49:51 +01:00
|
|
|
}
|
|
|
|
|
2007-06-06 18:40:48 +02:00
|
|
|
|
2004-08-21 01:37:40 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* MRLSplit: parse the access, demux and url part of the
|
|
|
|
* Media Resource Locator.
|
|
|
|
*****************************************************************************/
|
2018-04-16 16:52:33 +02:00
|
|
|
static void input_SplitMRL( const char **access, const char **demux,
|
|
|
|
const char **path, const char **anchor, char *buf )
|
2004-06-25 00:21:36 +02:00
|
|
|
{
|
2010-11-06 17:20:51 +01:00
|
|
|
char *p;
|
2004-06-25 00:21:36 +02:00
|
|
|
|
2010-11-06 17:20:51 +01:00
|
|
|
/* Separate <path> from <access>[/<demux>]:// */
|
2021-09-16 16:25:38 +02:00
|
|
|
p = strchr( buf, ':');
|
2010-11-06 17:20:51 +01:00
|
|
|
if( p != NULL )
|
2004-06-25 00:21:36 +02:00
|
|
|
{
|
2021-09-16 16:25:38 +02:00
|
|
|
*(p++) = '\0'; /* skips ':' */
|
|
|
|
*path = p + (strncmp(p, "//", 2) ? 0 : 2); /* skips "//" */
|
2010-03-03 18:12:57 +01:00
|
|
|
|
|
|
|
/* Remove HTML anchor if present (not supported).
|
|
|
|
* The hash symbol itself should be URI-encoded. */
|
2010-11-06 17:20:51 +01:00
|
|
|
p = strchr( p, '#' );
|
2011-09-25 15:56:18 +02:00
|
|
|
if( p != NULL )
|
|
|
|
{
|
|
|
|
*(p++) = '\0';
|
|
|
|
*anchor = p;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*anchor = "";
|
2004-06-25 00:21:36 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-03-01 22:22:46 +01:00
|
|
|
#ifndef NDEBUG
|
2010-11-06 17:20:51 +01:00
|
|
|
fprintf( stderr, "%s(\"%s\") probably not a valid URI!\n", __func__,
|
2011-09-25 15:56:18 +02:00
|
|
|
buf );
|
2010-03-01 22:22:46 +01:00
|
|
|
#endif
|
2010-11-06 17:20:51 +01:00
|
|
|
/* Note: this is a valid non const pointer to "": */
|
2011-09-25 15:56:18 +02:00
|
|
|
*path = buf + strlen( buf );
|
2010-11-06 17:20:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Separate access from demux */
|
2011-09-25 15:56:18 +02:00
|
|
|
p = strchr( buf, '/' );
|
2010-11-06 17:20:51 +01:00
|
|
|
if( p != NULL )
|
|
|
|
{
|
|
|
|
*(p++) = '\0';
|
|
|
|
if( p[0] == '$' )
|
|
|
|
p++;
|
2011-09-25 15:56:18 +02:00
|
|
|
*demux = p;
|
2004-06-25 00:21:36 +02:00
|
|
|
}
|
2010-11-06 17:20:51 +01:00
|
|
|
else
|
2011-09-25 15:56:18 +02:00
|
|
|
*demux = "";
|
2010-03-01 22:22:46 +01:00
|
|
|
|
2010-11-06 17:20:51 +01:00
|
|
|
/* We really don't want module name substitution here! */
|
2011-09-25 15:56:18 +02:00
|
|
|
p = buf;
|
2010-11-06 17:20:51 +01:00
|
|
|
if( p[0] == '$' )
|
|
|
|
p++;
|
2011-09-25 15:56:18 +02:00
|
|
|
*access = p;
|
2004-06-25 00:21:36 +02:00
|
|
|
}
|
2004-08-21 01:37:40 +02:00
|
|
|
|
2011-09-25 15:46:52 +02:00
|
|
|
static const char *MRLSeekPoint( const char *str, int *title, int *chapter )
|
2008-08-13 01:51:40 +02:00
|
|
|
{
|
|
|
|
char *end;
|
2011-09-25 15:46:52 +02:00
|
|
|
unsigned long u;
|
|
|
|
|
|
|
|
/* Look for the title */
|
|
|
|
u = strtoul( str, &end, 0 );
|
|
|
|
*title = (str == end || u > (unsigned long)INT_MAX) ? -1 : (int)u;
|
|
|
|
str = end;
|
|
|
|
|
|
|
|
/* Look for the chapter */
|
|
|
|
if( *str == ':' )
|
2008-08-13 01:51:40 +02:00
|
|
|
{
|
2011-09-25 15:46:52 +02:00
|
|
|
str++;
|
|
|
|
u = strtoul( str, &end, 0 );
|
|
|
|
*chapter = (str == end || u > (unsigned long)INT_MAX) ? -1 : (int)u;
|
|
|
|
str = end;
|
2008-08-13 01:51:40 +02:00
|
|
|
}
|
2011-09-25 15:46:52 +02:00
|
|
|
else
|
|
|
|
*chapter = -1;
|
|
|
|
|
|
|
|
return str;
|
2008-08-13 01:51:40 +02:00
|
|
|
}
|
|
|
|
|
2011-09-25 15:46:52 +02:00
|
|
|
|
2004-08-21 01:37:40 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* MRLSections: parse title and seekpoint info from the Media Resource Locator.
|
|
|
|
*
|
|
|
|
* Syntax:
|
2011-09-25 15:46:52 +02:00
|
|
|
* [url][@[title_start][:chapter_start][-[title_end][:chapter_end]]]
|
2004-08-21 01:37:40 +02:00
|
|
|
*****************************************************************************/
|
2011-09-25 15:56:18 +02:00
|
|
|
static void MRLSections( const char *p,
|
2004-08-21 01:37:40 +02:00
|
|
|
int *pi_title_start, int *pi_title_end,
|
|
|
|
int *pi_chapter_start, int *pi_chapter_end )
|
|
|
|
{
|
2011-09-25 15:46:52 +02:00
|
|
|
*pi_title_start = *pi_title_end = *pi_chapter_start = *pi_chapter_end = -1;
|
2004-08-21 01:37:40 +02:00
|
|
|
|
2011-09-25 15:46:52 +02:00
|
|
|
int title_start, chapter_start, title_end, chapter_end;
|
2004-08-21 01:37:40 +02:00
|
|
|
|
2011-10-31 02:17:17 +01:00
|
|
|
if( !p )
|
|
|
|
return;
|
|
|
|
|
2011-09-25 15:46:52 +02:00
|
|
|
if( *p != '-' )
|
|
|
|
p = MRLSeekPoint( p, &title_start, &chapter_start );
|
|
|
|
else
|
|
|
|
title_start = chapter_start = -1;
|
2004-08-21 01:37:40 +02:00
|
|
|
|
2011-09-25 15:46:52 +02:00
|
|
|
if( *p == '-' )
|
|
|
|
p = MRLSeekPoint( p + 1, &title_end, &chapter_end );
|
|
|
|
else
|
|
|
|
title_end = chapter_end = -1;
|
2004-08-21 01:37:40 +02:00
|
|
|
|
2011-09-25 15:46:52 +02:00
|
|
|
if( *p ) /* syntax error */
|
|
|
|
return;
|
2004-08-21 01:37:40 +02:00
|
|
|
|
2011-09-25 15:46:52 +02:00
|
|
|
*pi_title_start = title_start;
|
|
|
|
*pi_title_end = title_end;
|
|
|
|
*pi_chapter_start = chapter_start;
|
|
|
|
*pi_chapter_end = chapter_end;
|
2004-08-21 01:37:40 +02:00
|
|
|
}
|
2006-06-09 06:38:16 +02:00
|
|
|
|
2016-06-07 17:19:19 +02:00
|
|
|
static int input_SlaveSourceAdd( input_thread_t *p_input,
|
|
|
|
enum slave_type i_type, const char *psz_uri,
|
|
|
|
unsigned i_flags )
|
2006-06-09 06:38:16 +02:00
|
|
|
{
|
2018-07-23 12:05:54 +02:00
|
|
|
input_thread_private_t *priv = input_priv(p_input);
|
2016-06-07 17:19:19 +02:00
|
|
|
const char *psz_forced_demux;
|
|
|
|
const bool b_can_fail = i_flags & SLAVE_ADD_CANFAIL;
|
|
|
|
const bool b_forced = i_flags & SLAVE_ADD_FORCED;
|
|
|
|
const bool b_set_time = i_flags & SLAVE_ADD_SET_TIME;
|
2013-12-06 14:09:01 +01:00
|
|
|
|
2016-06-07 17:19:19 +02:00
|
|
|
switch( i_type )
|
|
|
|
{
|
|
|
|
case SLAVE_TYPE_SPU:
|
|
|
|
psz_forced_demux = "subtitle";
|
|
|
|
break;
|
2021-04-22 14:25:22 +02:00
|
|
|
case SLAVE_TYPE_GENERIC:
|
2016-06-07 17:19:19 +02:00
|
|
|
psz_forced_demux = NULL;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
vlc_assert_unreachable();
|
|
|
|
}
|
2013-12-06 14:09:01 +01:00
|
|
|
|
2018-07-23 12:11:57 +02:00
|
|
|
msg_Dbg( p_input, "loading %s slave: %s (forced: %d)",
|
2021-04-22 14:19:31 +02:00
|
|
|
i_type == SLAVE_TYPE_SPU ? "spu" : "generic", psz_uri, b_forced );
|
2015-10-24 19:57:33 +02:00
|
|
|
|
2020-02-26 13:09:26 +01:00
|
|
|
input_source_t *p_source = InputSourceNew( psz_uri );
|
2020-02-26 14:43:13 +01:00
|
|
|
if( !p_source )
|
|
|
|
return VLC_EGENERIC;
|
|
|
|
|
2020-02-28 14:07:14 +01:00
|
|
|
if( b_forced )
|
2021-04-22 14:11:31 +02:00
|
|
|
p_source->autoselected = true;
|
2020-02-28 14:07:14 +01:00
|
|
|
|
2020-02-26 14:43:13 +01:00
|
|
|
int ret = InputSourceInit( p_source, p_input, psz_uri,
|
|
|
|
psz_forced_demux,
|
|
|
|
b_can_fail || psz_forced_demux );
|
2017-10-26 17:32:24 +02:00
|
|
|
|
2020-02-26 14:43:13 +01:00
|
|
|
if( psz_forced_demux && ret != VLC_SUCCESS )
|
|
|
|
ret = InputSourceInit( p_source, p_input, psz_uri, NULL, b_can_fail );
|
2017-10-26 17:32:24 +02:00
|
|
|
|
2020-02-26 14:43:13 +01:00
|
|
|
if( ret != VLC_SUCCESS )
|
2016-06-07 17:19:19 +02:00
|
|
|
{
|
|
|
|
msg_Warn( p_input, "failed to add %s as slave", psz_uri );
|
2022-04-01 22:25:14 +02:00
|
|
|
goto error;
|
2016-06-07 17:19:19 +02:00
|
|
|
}
|
|
|
|
|
2021-04-22 14:25:22 +02:00
|
|
|
if( i_type == SLAVE_TYPE_GENERIC )
|
2016-06-07 17:19:19 +02:00
|
|
|
{
|
|
|
|
if( b_set_time )
|
|
|
|
{
|
2018-05-05 15:28:18 +02:00
|
|
|
vlc_tick_t i_time;
|
2016-06-07 17:19:19 +02:00
|
|
|
|
|
|
|
/* Set position */
|
2018-07-23 12:05:54 +02:00
|
|
|
if( demux_Control( priv->master->p_demux, DEMUX_GET_TIME, &i_time ) )
|
2016-06-07 17:19:19 +02:00
|
|
|
{
|
|
|
|
msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
|
2022-04-01 22:23:23 +02:00
|
|
|
goto error;
|
2016-06-07 17:19:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if( demux_Control( p_source->p_demux,
|
|
|
|
DEMUX_SET_TIME, i_time, true ) )
|
|
|
|
{
|
|
|
|
msg_Err( p_input, "seek failed for new slave" );
|
2022-04-01 22:23:23 +02:00
|
|
|
goto error;
|
2016-06-07 17:19:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get meta (access and demux) */
|
|
|
|
InputUpdateMeta( p_input, p_source->p_demux );
|
|
|
|
}
|
2018-10-17 14:43:14 +02:00
|
|
|
else
|
|
|
|
p_source->b_slave_sub = true;
|
2016-06-07 17:19:19 +02:00
|
|
|
|
2018-07-23 12:05:54 +02:00
|
|
|
TAB_APPEND( priv->i_slave, priv->slave, p_source );
|
2016-06-07 17:19:19 +02:00
|
|
|
|
|
|
|
return VLC_SUCCESS;
|
2022-04-01 22:23:23 +02:00
|
|
|
|
|
|
|
error:
|
|
|
|
InputSourceDestroy( p_source );
|
|
|
|
input_source_Release( p_source );
|
|
|
|
return VLC_EGENERIC;
|
2013-12-06 14:09:01 +01:00
|
|
|
}
|
|
|
|
|
2016-03-25 13:56:11 +01:00
|
|
|
static char *input_SubtitleFile2Uri( input_thread_t *p_input,
|
|
|
|
const char *psz_subtitle )
|
2013-12-06 14:09:01 +01:00
|
|
|
{
|
2006-06-16 21:05:55 +02:00
|
|
|
/* if we are provided a subtitle.sub file,
|
|
|
|
* see if we don't have a subtitle.idx and use it instead */
|
2016-02-13 17:05:55 +01:00
|
|
|
char *psz_idxpath = NULL;
|
2016-03-25 13:56:11 +01:00
|
|
|
char *psz_extension = strrchr( psz_subtitle, '.');
|
2016-02-13 17:05:55 +01:00
|
|
|
if( psz_extension && strcmp( psz_extension, ".sub" ) == 0 )
|
2006-06-16 21:05:55 +02:00
|
|
|
{
|
2016-02-13 17:05:55 +01:00
|
|
|
psz_idxpath = strdup( psz_subtitle );
|
|
|
|
if( psz_idxpath )
|
2006-06-16 21:05:55 +02:00
|
|
|
{
|
2008-09-18 20:15:29 +02:00
|
|
|
struct stat st;
|
2006-06-16 21:05:55 +02:00
|
|
|
|
2016-02-13 17:05:55 +01:00
|
|
|
psz_extension = psz_extension - psz_subtitle + psz_idxpath;
|
2006-06-16 21:05:55 +02:00
|
|
|
strcpy( psz_extension, ".idx" );
|
2008-09-18 20:15:29 +02:00
|
|
|
|
2016-02-13 17:05:55 +01:00
|
|
|
if( !vlc_stat( psz_idxpath, &st ) && S_ISREG( st.st_mode ) )
|
2006-06-16 21:05:55 +02:00
|
|
|
{
|
2013-03-14 16:32:24 +01:00
|
|
|
msg_Dbg( p_input, "using %s as subtitle file instead of %s",
|
2016-02-13 17:05:55 +01:00
|
|
|
psz_idxpath, psz_subtitle );
|
|
|
|
psz_subtitle = psz_idxpath;
|
2006-06-16 21:05:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-27 16:10:15 +02:00
|
|
|
char *psz_uri = vlc_path2uri( psz_subtitle, NULL );
|
|
|
|
free( psz_idxpath );
|
|
|
|
return psz_uri;
|
2008-09-18 20:15:29 +02:00
|
|
|
}
|
|
|
|
|
2018-09-04 16:15:04 +02:00
|
|
|
int input_GetAttachments(input_thread_t *input,
|
|
|
|
input_attachment_t ***attachments)
|
|
|
|
{
|
|
|
|
input_thread_private_t *priv = input_priv(input);
|
|
|
|
|
|
|
|
vlc_mutex_lock(&priv->p_item->lock);
|
|
|
|
int attachments_count = priv->i_attachment;
|
|
|
|
if (attachments_count <= 0)
|
|
|
|
{
|
|
|
|
vlc_mutex_unlock(&priv->p_item->lock);
|
2018-09-21 03:41:29 +02:00
|
|
|
*attachments = NULL;
|
2018-09-04 16:15:04 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
*attachments = vlc_alloc(attachments_count, sizeof(input_attachment_t*));
|
|
|
|
if (!*attachments)
|
2020-11-10 16:39:38 +01:00
|
|
|
{
|
|
|
|
vlc_mutex_unlock(&priv->p_item->lock);
|
2018-09-04 16:15:04 +02:00
|
|
|
return -1;
|
2020-11-10 16:39:38 +01:00
|
|
|
}
|
2018-09-04 16:15:04 +02:00
|
|
|
|
|
|
|
for (int i = 0; i < attachments_count; i++)
|
2020-10-27 17:14:28 +01:00
|
|
|
(*attachments)[i] = vlc_input_attachment_Hold(priv->attachment[i]);
|
2018-09-04 16:15:04 +02:00
|
|
|
|
|
|
|
vlc_mutex_unlock(&priv->p_item->lock);
|
|
|
|
return attachments_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
input_attachment_t *input_GetAttachment(input_thread_t *input, const char *name)
|
|
|
|
{
|
|
|
|
input_thread_private_t *priv = input_priv(input);
|
|
|
|
|
|
|
|
vlc_mutex_lock(&priv->p_item->lock);
|
|
|
|
for (int i = 0; i < priv->i_attachment; i++)
|
|
|
|
{
|
|
|
|
if (!strcmp( priv->attachment[i]->psz_name, name))
|
|
|
|
{
|
|
|
|
input_attachment_t *attachment =
|
2020-10-27 17:14:28 +01:00
|
|
|
vlc_input_attachment_Hold(priv->attachment[i] );
|
2018-09-04 16:15:04 +02:00
|
|
|
vlc_mutex_unlock( &priv->p_item->lock );
|
|
|
|
return attachment;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
vlc_mutex_unlock( &priv->p_item->lock );
|
|
|
|
return NULL;
|
|
|
|
}
|
2021-04-27 13:19:53 +02:00
|
|
|
|
|
|
|
bool input_CanPaceControl(input_thread_t *input)
|
|
|
|
{
|
|
|
|
input_thread_private_t *priv = input_priv(input);
|
2021-04-27 13:33:21 +02:00
|
|
|
return priv->master->b_can_pace_control;
|
2021-04-27 13:19:53 +02:00
|
|
|
}
|