mirror of
https://github.com/mpv-player/mpv
synced 2024-12-24 07:42:17 +00:00
2d958dbf2b
Even though only 1 seek range is supported at the time. Other than preparation for possibly future features, the main gain is actually that we finally separate the reporting for the buffering, and the seek ranges. These can be subtly different, so it's good to have a clear separation. This commit also fixes that the ts_reader wasn't rebased to the start time, which could make the player show "???" for buffered cache amount in some .ts files and others (especially at the end, when ts_reader could become higher than ts_max). It also fixes writing the cache-end field in the demuxer-cache-state property: it checked ts_start against NOPTS, which makes no sense. ts_start was never used (except for the bug mentioned above), so get rid of it completely. This also makes it convenient to move the segment check for last_ts to the demux_add_packet() function.
310 lines
10 KiB
C
310 lines
10 KiB
C
/*
|
|
* This file is part of mpv.
|
|
*
|
|
* mpv 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 (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 Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef MPLAYER_DEMUXER_H
|
|
#define MPLAYER_DEMUXER_H
|
|
|
|
#include <sys/types.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
|
|
#include "misc/bstr.h"
|
|
#include "common/common.h"
|
|
#include "common/tags.h"
|
|
#include "packet.h"
|
|
#include "stheader.h"
|
|
|
|
enum demux_ctrl {
|
|
DEMUXER_CTRL_SWITCHED_TRACKS = 1,
|
|
DEMUXER_CTRL_RESYNC,
|
|
DEMUXER_CTRL_IDENTIFY_PROGRAM,
|
|
DEMUXER_CTRL_STREAM_CTRL,
|
|
DEMUXER_CTRL_GET_READER_STATE,
|
|
DEMUXER_CTRL_GET_BITRATE_STATS, // double[STREAM_TYPE_COUNT]
|
|
DEMUXER_CTRL_REPLACE_STREAM,
|
|
};
|
|
|
|
#define MAX_SEEK_RANGES 1
|
|
|
|
struct demux_seek_range {
|
|
double start, end;
|
|
};
|
|
|
|
struct demux_ctrl_reader_state {
|
|
bool eof, underrun, idle;
|
|
double ts_duration;
|
|
double ts_reader; // approx. timerstamp of decoder position
|
|
double ts_end; // approx. timestamp of end of buffered range
|
|
// Positions that can be seeked to without incurring the latency of a low
|
|
// level seek.
|
|
int num_seek_ranges;
|
|
struct demux_seek_range seek_ranges[MAX_SEEK_RANGES];
|
|
};
|
|
|
|
struct demux_ctrl_stream_ctrl {
|
|
int ctrl;
|
|
void *arg;
|
|
int res;
|
|
};
|
|
|
|
#define SEEK_FACTOR (1 << 1) // argument is in range [0,1]
|
|
#define SEEK_FORWARD (1 << 2) // prefer later time if not exact
|
|
// (if unset, prefer earlier time)
|
|
#define SEEK_HR (1 << 5) // hr-seek (this is a weak hint only)
|
|
|
|
// Strictness of the demuxer open format check.
|
|
// demux.c will try by default: NORMAL, UNSAFE (in this order)
|
|
// Using "-demuxer format" will try REQUEST
|
|
// Using "-demuxer +format" will try FORCE
|
|
// REQUEST can be used as special value for raw demuxers which have no file
|
|
// header check; then they should fail if check!=FORCE && check!=REQUEST.
|
|
//
|
|
// In general, the list is sorted from weakest check to normal check.
|
|
// You can use relation operators to compare the check level.
|
|
enum demux_check {
|
|
DEMUX_CHECK_FORCE, // force format if possible
|
|
DEMUX_CHECK_UNSAFE, // risky/fuzzy detection
|
|
DEMUX_CHECK_REQUEST,// requested by user or stream implementation
|
|
DEMUX_CHECK_NORMAL, // normal, safe detection
|
|
};
|
|
|
|
enum demux_event {
|
|
DEMUX_EVENT_INIT = 1 << 0, // complete (re-)initialization
|
|
DEMUX_EVENT_STREAMS = 1 << 1, // a stream was added
|
|
DEMUX_EVENT_METADATA = 1 << 2, // metadata or stream_metadata changed
|
|
DEMUX_EVENT_ALL = 0xFFFF,
|
|
};
|
|
|
|
struct demuxer;
|
|
struct timeline;
|
|
|
|
/**
|
|
* Demuxer description structure
|
|
*/
|
|
typedef struct demuxer_desc {
|
|
const char *name; // Demuxer name, used with -demuxer switch
|
|
const char *desc; // Displayed to user
|
|
|
|
// Return 0 on success, otherwise -1
|
|
int (*open)(struct demuxer *demuxer, enum demux_check check);
|
|
// The following functions are all optional
|
|
int (*fill_buffer)(struct demuxer *demuxer); // 0 on EOF, otherwise 1
|
|
void (*close)(struct demuxer *demuxer);
|
|
void (*seek)(struct demuxer *demuxer, double rel_seek_secs, int flags);
|
|
int (*control)(struct demuxer *demuxer, int cmd, void *arg);
|
|
// See timeline.c
|
|
void (*load_timeline)(struct timeline *tl);
|
|
} demuxer_desc_t;
|
|
|
|
typedef struct demux_chapter
|
|
{
|
|
int original_index;
|
|
double pts;
|
|
struct mp_tags *metadata;
|
|
uint64_t demuxer_id; // for mapping to internal demuxer data structures
|
|
} demux_chapter_t;
|
|
|
|
struct demux_edition {
|
|
uint64_t demuxer_id;
|
|
bool default_edition;
|
|
struct mp_tags *metadata;
|
|
};
|
|
|
|
struct matroska_segment_uid {
|
|
unsigned char segment[16];
|
|
uint64_t edition;
|
|
};
|
|
|
|
struct matroska_data {
|
|
struct matroska_segment_uid uid;
|
|
// Ordered chapter information if any
|
|
struct matroska_chapter {
|
|
uint64_t start;
|
|
uint64_t end;
|
|
bool has_segment_uid;
|
|
struct matroska_segment_uid uid;
|
|
char *name;
|
|
} *ordered_chapters;
|
|
int num_ordered_chapters;
|
|
};
|
|
|
|
struct replaygain_data {
|
|
float track_gain;
|
|
float track_peak;
|
|
float album_gain;
|
|
float album_peak;
|
|
};
|
|
|
|
typedef struct demux_attachment
|
|
{
|
|
char *name;
|
|
char *type;
|
|
void *data;
|
|
unsigned int data_size;
|
|
} demux_attachment_t;
|
|
|
|
struct demuxer_params {
|
|
char *force_format;
|
|
int matroska_num_wanted_uids;
|
|
struct matroska_segment_uid *matroska_wanted_uids;
|
|
int matroska_wanted_segment;
|
|
bool *matroska_was_valid;
|
|
struct timeline *timeline;
|
|
bool disable_timeline;
|
|
bool initial_readahead;
|
|
bstr init_fragment;
|
|
bool skip_lavf_probing;
|
|
// -- demux_open_url() only
|
|
int stream_flags;
|
|
bool disable_cache;
|
|
// result
|
|
bool demuxer_failed;
|
|
};
|
|
|
|
typedef struct demuxer {
|
|
const demuxer_desc_t *desc; ///< Demuxer description structure
|
|
const char *filetype; // format name when not identified by demuxer (libavformat)
|
|
int64_t filepos; // input stream current pos.
|
|
char *filename; // same as stream->url
|
|
bool seekable;
|
|
bool partially_seekable; // true if _maybe_ seekable; implies seekable=true
|
|
double start_time;
|
|
double duration; // -1 if unknown
|
|
// File format allows PTS resets (even if the current file is without)
|
|
bool ts_resets_possible;
|
|
// The file data was fully read, and there is no need to keep the stream
|
|
// open, keep the cache active, or to run the demuxer thread. Generating
|
|
// packets is not slow either (unlike e.g. libavdevice pseudo-demuxers).
|
|
// Typical examples: text subtitles, playlists
|
|
bool fully_read;
|
|
bool is_network; // opened directly from a network stream
|
|
bool access_references; // allow opening other files/URLs
|
|
|
|
// Bitmask of DEMUX_EVENT_*
|
|
int events;
|
|
|
|
struct demux_edition *editions;
|
|
int num_editions;
|
|
int edition;
|
|
|
|
struct demux_chapter *chapters;
|
|
int num_chapters;
|
|
|
|
struct demux_attachment *attachments;
|
|
int num_attachments;
|
|
|
|
struct matroska_data matroska_data;
|
|
|
|
// If the file is a playlist file
|
|
struct playlist *playlist;
|
|
|
|
struct mp_tags *metadata;
|
|
|
|
void *priv; // demuxer-specific internal data
|
|
struct mpv_global *global;
|
|
struct mp_log *log, *glog;
|
|
struct demuxer_params *params;
|
|
|
|
// internal to demux.c
|
|
struct demux_internal *in;
|
|
struct mp_tags **update_stream_tags;
|
|
int num_update_stream_tags;
|
|
|
|
// Since the demuxer can run in its own thread, and the stream is not
|
|
// thread-safe, only the demuxer is allowed to access the stream directly.
|
|
// You can freely use demux_stream_control() to send STREAM_CTRLs, or use
|
|
// demux_pause() to get exclusive access to the stream.
|
|
// Also note that the stream can get replaced if fully_read is set.
|
|
struct stream *stream;
|
|
} demuxer_t;
|
|
|
|
typedef struct {
|
|
int progid; //program id
|
|
int aid, vid, sid; //audio, video and subtitle id
|
|
} demux_program_t;
|
|
|
|
void free_demuxer(struct demuxer *demuxer);
|
|
void free_demuxer_and_stream(struct demuxer *demuxer);
|
|
|
|
void demux_add_packet(struct sh_stream *stream, demux_packet_t *dp);
|
|
void demuxer_feed_caption(struct sh_stream *stream, demux_packet_t *dp);
|
|
|
|
struct demux_packet *demux_read_packet(struct sh_stream *sh);
|
|
int demux_read_packet_async(struct sh_stream *sh, struct demux_packet **out_pkt);
|
|
bool demux_stream_is_selected(struct sh_stream *stream);
|
|
bool demux_has_packet(struct sh_stream *sh);
|
|
struct demux_packet *demux_read_any_packet(struct demuxer *demuxer);
|
|
|
|
struct sh_stream *demux_get_stream(struct demuxer *demuxer, int index);
|
|
int demux_get_num_stream(struct demuxer *demuxer);
|
|
|
|
struct sh_stream *demux_alloc_sh_stream(enum stream_type type);
|
|
void demux_add_sh_stream(struct demuxer *demuxer, struct sh_stream *sh);
|
|
|
|
struct demuxer *demux_open(struct stream *stream, struct demuxer_params *params,
|
|
struct mpv_global *global);
|
|
|
|
struct mp_cancel;
|
|
struct demuxer *demux_open_url(const char *url,
|
|
struct demuxer_params *params,
|
|
struct mp_cancel *cancel,
|
|
struct mpv_global *global);
|
|
|
|
void demux_start_thread(struct demuxer *demuxer);
|
|
void demux_stop_thread(struct demuxer *demuxer);
|
|
void demux_set_wakeup_cb(struct demuxer *demuxer, void (*cb)(void *ctx), void *ctx);
|
|
|
|
bool demux_cancel_test(struct demuxer *demuxer);
|
|
|
|
void demux_flush(struct demuxer *demuxer);
|
|
int demux_seek(struct demuxer *demuxer, double rel_seek_secs, int flags);
|
|
void demux_set_ts_offset(struct demuxer *demuxer, double offset);
|
|
|
|
int demux_control(struct demuxer *demuxer, int cmd, void *arg);
|
|
|
|
void demuxer_select_track(struct demuxer *demuxer, struct sh_stream *stream,
|
|
double ref_pts, bool selected);
|
|
void demux_set_stream_autoselect(struct demuxer *demuxer, bool autoselect);
|
|
|
|
void demuxer_help(struct mp_log *log);
|
|
|
|
int demuxer_add_attachment(struct demuxer *demuxer, char *name,
|
|
char *type, void *data, size_t data_size);
|
|
int demuxer_add_chapter(demuxer_t *demuxer, char *name,
|
|
double pts, uint64_t demuxer_id);
|
|
void demux_set_stream_tags(struct demuxer *demuxer, struct sh_stream *sh,
|
|
struct mp_tags *tags);
|
|
|
|
int demux_stream_control(demuxer_t *demuxer, int ctrl, void *arg);
|
|
|
|
void demux_changed(demuxer_t *demuxer, int events);
|
|
void demux_update(demuxer_t *demuxer);
|
|
|
|
struct sh_stream *demuxer_stream_by_demuxer_id(struct demuxer *d,
|
|
enum stream_type t, int id);
|
|
|
|
struct demux_chapter *demux_copy_chapter_data(struct demux_chapter *c, int num);
|
|
|
|
bool demux_matroska_uid_cmp(struct matroska_segment_uid *a,
|
|
struct matroska_segment_uid *b);
|
|
|
|
const char *stream_type_name(enum stream_type type);
|
|
|
|
#endif /* MPLAYER_DEMUXER_H */
|