/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <pthread.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "config.h"
#include "options/options.h"
#include "talloc.h"
#include "common/msg.h"
#include "common/global.h"
#include "osdep/threads.h"
#include "stream/stream.h"
#include "demux.h"
#include "stheader.h"
#include "audio/format.h"
// Demuxer list
extern const struct demuxer_desc demuxer_desc_edl;
extern const struct demuxer_desc demuxer_desc_cue;
extern const demuxer_desc_t demuxer_desc_rawaudio;
extern const demuxer_desc_t demuxer_desc_rawvideo;
extern const demuxer_desc_t demuxer_desc_tv;
extern const demuxer_desc_t demuxer_desc_mf;
extern const demuxer_desc_t demuxer_desc_matroska;
extern const demuxer_desc_t demuxer_desc_lavf;
extern const demuxer_desc_t demuxer_desc_libass;
extern const demuxer_desc_t demuxer_desc_subreader;
extern const demuxer_desc_t demuxer_desc_playlist;
extern const demuxer_desc_t demuxer_desc_disc;
extern const demuxer_desc_t demuxer_desc_rar;
/* Please do not add any new demuxers here. If you want to implement a new
* demuxer, add it to libavformat, except for wrappers around external
* libraries and demuxers requiring binary support. */
const demuxer_desc_t *const demuxer_list[] = {
&demuxer_desc_disc,
&demuxer_desc_edl,
&demuxer_desc_cue,
&demuxer_desc_rawaudio,
&demuxer_desc_rawvideo,
#if HAVE_TV
&demuxer_desc_tv,
#endif
#if HAVE_LIBASS
&demuxer_desc_libass,
#endif
&demuxer_desc_matroska,
&demuxer_desc_rar,
&demuxer_desc_lavf,
&demuxer_desc_mf,
&demuxer_desc_playlist,
// Pretty aggressive, so should be last.
&demuxer_desc_subreader,
NULL
};
struct demux_internal {
struct mp_log *log;
// The demuxer runs potentially in another thread, so we keep two demuxer
// structs; the real demuxer can access the shadow struct only.
// Since demuxer and user threads both don't use locks, a third demuxer
// struct d_buffer is used to copy data between them in a synchronized way.
struct demuxer *d_thread; // accessed by demuxer impl. (producer)
struct demuxer *d_user; // accessed by player (consumer)
struct demuxer *d_buffer; // protected by lock; used to sync d_user/thread
// The lock protects the packet queues (struct demux_stream), d_buffer,
// and some minor fields like thread_paused.
pthread_mutex_t lock;
pthread_cond_t wakeup;
pthread_t thread;
// -- All the following fields are protected by lock.
bool thread_paused;
int thread_request_pause; // counter, if >0, make demuxer thread pause
bool thread_terminate;
bool threading;
void (*wakeup_cb)(void *ctx);
void *wakeup_cb_ctx;
bool warned_queue_overflow;
bool last_eof; // last actual global EOF status
bool eof; // whether we're in EOF state (reset for retry)
bool idle;
bool autoselect;
double min_secs;
int min_packs;
int min_bytes;
bool tracks_switched; // thread needs to inform demuxer of this
bool seeking; // there's a seek queued
int seek_flags; // flags for next seek (if seeking==true)
double seek_pts;
bool refresh_seeks_enabled;
bool start_refresh_seek;
// Cached state.
bool force_cache_update;
double time_length;
struct mp_nav_event *nav_event;
struct mp_tags *stream_metadata;
int64_t stream_size;
int64_t stream_cache_size;
int64_t stream_cache_fill;
int stream_cache_idle;
// Updated during init only.
char *stream_base_filename;
};
struct demux_stream {
struct demux_internal *in;
enum stream_type type;
// all fields are protected by in->lock
bool selected; // user wants packets from this stream
bool active; // try to keep at least 1 packet queued
// if false, this stream is disabled, or passively
// read (like subtitles)
bool eof; // end of demuxed stream? (true if all buffer empty)
bool refreshing;
size_t packs; // number of packets in buffer
size_t bytes; // total bytes of packets in buffer
double base_ts; // timestamp of the last packet returned to decoder
double last_ts; // timestamp of the last packet added to queue
double last_br_ts; // timestamp of last packet bitrate was calculated
size_t last_br_bytes; // summed packet sizes since last bitrate calculation
double bitrate;
int64_t last_pos;
struct demux_packet *head;
struct demux_packet *tail;
};
// Return "a", or if that is NOPTS, return "def".
#define PTS_OR_DEF(a, def) ((a) == MP_NOPTS_VALUE ? (def) : (a))
// If one of the values is NOPTS, always pick the other one.
#define MP_PTS_MIN(a, b) MPMIN(PTS_OR_DEF(a, b), PTS_OR_DEF(b, a))
#define MP_PTS_MAX(a, b) MPMAX(PTS_OR_DEF(a, b), PTS_OR_DEF(b, a))
static void demuxer_sort_chapters(demuxer_t *demuxer);
static void *demux_thread(void *pctx);
static void update_cache(struct demux_internal *in);
// called locked
static void ds_flush(struct demux_stream *ds)
{
demux_packet_t *dp = ds->head;
while (dp) {
demux_packet_t *dn = dp->next;
free_demux_packet(dp);
dp = dn;
}
ds->head = ds->tail = NULL;
ds->packs = 0;
ds->bytes = 0;
ds->last_ts = ds->base_ts = ds->last_br_ts = MP_NOPTS_VALUE;
ds->last_br_bytes = 0;
ds->bitrate = -1;
ds->eof = false;
ds->active = false;
ds->refreshing = false;
ds->last_pos = -1;
}
struct sh_stream *new_sh_stream(demuxer_t *demuxer, enum stream_type type)
{
assert(demuxer == demuxer->in->d_thread);
if (demuxer->num_streams > MAX_SH_STREAMS) {
MP_WARN(demuxer, "Too many streams.\n");
return NULL;
}
int demuxer_id = 0;
for (int n = 0; n < demuxer->num_streams; n++) {
if (demuxer->streams[n]->type == type)
demuxer_id++;
}
struct sh_stream *sh = talloc_ptrtype(demuxer, sh);
*sh = (struct sh_stream) {
.type = type,
.index = demuxer->num_streams,
.ff_index = demuxer->num_streams,
.demuxer_id = demuxer_id, // may be overwritten by demuxer
.ds = talloc(sh, struct demux_stream),
};
*sh->ds = (struct demux_stream) {
.in = demuxer->in,
.type = sh->type,
.selected = demuxer->in->autoselect,
};
MP_TARRAY_APPEND(demuxer, demuxer->streams, demuxer->num_streams, sh);
switch (sh->type) {
case STREAM_VIDEO: sh->video = talloc_zero(demuxer, struct sh_video); break;
case STREAM_AUDIO: sh->audio = talloc_zero(demuxer, struct sh_audio); break;
case STREAM_SUB: sh->sub = talloc_zero(demuxer, struct sh_sub); break;
}
return sh;
}
void free_demuxer(demuxer_t *demuxer)
{
if (!demuxer)
return;
struct demux_internal *in = demuxer->in;
assert(demuxer == in->d_user);
demux_stop_thread(demuxer);
if (demuxer->desc->close)
demuxer->desc->close(in->d_thread);
for (int n = 0; n < demuxer->num_streams; n++)
ds_flush(demuxer->streams[n]->ds);
pthread_mutex_destroy(&in->lock);
pthread_cond_destroy(&in-
|