mirror of
https://github.com/mpv-player/mpv
synced 2024-12-24 07:33:46 +01:00
sub, demux: identify subtitle types with the codec name
Get rid of the 1-char subtitle type field. Use sh_stream->codec instead just like audio and video do. Use codec names as defined by libavcodec for simplicity, even if they're somewhat verbose and annoying. Note that ffmpeg might switch to "ass" as codec name for ASS, so we don't bother with the current silly "ssa" name.
This commit is contained in:
parent
5ac50f88c9
commit
331982b99c
@ -275,10 +275,8 @@ static void print_stream(struct MPContext *mpctx, struct track *t, int id)
|
||||
if (t->title)
|
||||
mp_msg(MSGT_CPLAYER, MSGL_INFO, " '%s'", t->title);
|
||||
const char *codec = s ? s->codec : NULL;
|
||||
if (s && t->type == STREAM_SUB)
|
||||
codec = sh_sub_type2str(s->sub->type);
|
||||
if (t->sh_sub) // external subs hack
|
||||
codec = sh_sub_type2str(t->sh_sub->type);
|
||||
codec = t->sh_sub->gsh->codec;
|
||||
mp_msg(MSGT_CPLAYER, MSGL_INFO, " (%s)", codec ? codec : "<unknown>");
|
||||
if (t->is_external)
|
||||
mp_msg(MSGT_CPLAYER, MSGL_INFO, " (external)");
|
||||
@ -1724,7 +1722,7 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl)
|
||||
struct demux_stream *d_sub = sh_sub ? sh_sub->ds : NULL;
|
||||
unsigned char *packet = NULL;
|
||||
int len;
|
||||
int type = sh_sub ? sh_sub->type : '\0';
|
||||
const char *type = sh_sub ? sh_sub->gsh->codec : NULL;
|
||||
|
||||
mpctx->osd->sub_offset = mpctx->video_offset;
|
||||
|
||||
@ -1747,7 +1745,7 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl)
|
||||
}
|
||||
|
||||
// DVD sub:
|
||||
if (type == 'v' && !(sh_sub && sh_sub->active)) {
|
||||
if (is_dvd_sub(type) && !(sh_sub && sh_sub->active)) {
|
||||
int timestamp;
|
||||
// Get a sub packet from the demuxer (or the vobsub.c thing, which
|
||||
// should be a demuxer, but isn't).
|
||||
@ -1808,7 +1806,7 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl)
|
||||
mp_dbg(MSGT_CPLAYER, MSGL_V, "Sub: c_pts=%5.3f s_pts=%5.3f "
|
||||
"duration=%5.3f len=%d\n", curpts_s, subpts_s, duration,
|
||||
len);
|
||||
if (type == 'm') {
|
||||
if (type && strcmp(type, "mov_text") == 0) {
|
||||
if (len < 2)
|
||||
continue;
|
||||
len = FFMIN(len - 2, AV_RB16(packet));
|
||||
@ -1820,7 +1818,7 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl)
|
||||
// text sub
|
||||
if (duration < 0)
|
||||
sub_clear_text(&mpctx->subs, MP_NOPTS_VALUE);
|
||||
if (type == 'a') { // ssa/ass subs without libass => convert to plaintext
|
||||
if (is_ass_sub(type)) { // ssa/ass subs without libass => convert to plaintext
|
||||
int i;
|
||||
unsigned char *p = packet;
|
||||
for (i = 0; i < 8 && *p != '\0'; p++)
|
||||
@ -1977,7 +1975,7 @@ static void reinit_subs(struct MPContext *mpctx)
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 40, 0)
|
||||
broken_lavc = true;
|
||||
#endif
|
||||
if (mpctx->sh_sub->type == 'v' && track->demuxer
|
||||
if (is_dvd_sub(mpctx->sh_sub->gsh->codec) && track->demuxer
|
||||
&& (track->demuxer->type == DEMUXER_TYPE_MPEG_PS || broken_lavc))
|
||||
init_vo_spudec(mpctx);
|
||||
else
|
||||
|
@ -241,21 +241,6 @@ demuxer_t *new_demuxer(struct MPOpts *opts, stream_t *stream, int type,
|
||||
return d;
|
||||
}
|
||||
|
||||
const char *sh_sub_type2str(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case 't': return "text";
|
||||
case 'm': return "movtext";
|
||||
case 'a': return "ass";
|
||||
case 'v': return "vobsub";
|
||||
case 'x': return "xsub";
|
||||
case 'b': return "dvb";
|
||||
case 'd': return "dvb-teletext";
|
||||
case 'p': return "hdmv pgs";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static struct sh_stream *new_sh_stream_id(demuxer_t *demuxer,
|
||||
enum stream_type type,
|
||||
int stream_index,
|
||||
|
@ -387,32 +387,11 @@ static void handle_stream(demuxer_t *demuxer, int i)
|
||||
}
|
||||
case AVMEDIA_TYPE_SUBTITLE: {
|
||||
sh_sub_t *sh_sub;
|
||||
char type;
|
||||
if (codec->codec_id == AV_CODEC_ID_TEXT ||
|
||||
codec->codec_id == AV_CODEC_ID_SUBRIP)
|
||||
type = 't';
|
||||
else if (codec->codec_id == AV_CODEC_ID_MOV_TEXT)
|
||||
type = 'm';
|
||||
else if (codec->codec_id == AV_CODEC_ID_SSA)
|
||||
type = 'a';
|
||||
else if (codec->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
|
||||
type = 'v';
|
||||
else if (codec->codec_id == AV_CODEC_ID_XSUB)
|
||||
type = 'x';
|
||||
else if (codec->codec_id == AV_CODEC_ID_DVB_SUBTITLE)
|
||||
type = 'b';
|
||||
else if (codec->codec_id == AV_CODEC_ID_DVB_TELETEXT)
|
||||
type = 'd';
|
||||
else if (codec->codec_id == AV_CODEC_ID_HDMV_PGS_SUBTITLE)
|
||||
type = 'p';
|
||||
else
|
||||
break;
|
||||
sh = new_sh_stream(demuxer, STREAM_SUB);
|
||||
if (!sh)
|
||||
break;
|
||||
sh_sub = sh->sub;
|
||||
|
||||
sh_sub->type = type;
|
||||
if (codec->extradata_size) {
|
||||
sh_sub->extradata = malloc(codec->extradata_size);
|
||||
memcpy(sh_sub->extradata, codec->extradata, codec->extradata_size);
|
||||
|
@ -133,8 +133,6 @@ typedef struct mkv_track {
|
||||
int fix_i_bps;
|
||||
double qt_last_a_pts;
|
||||
|
||||
int subtitle_type;
|
||||
|
||||
/* generic content encoding support */
|
||||
mkv_content_encoding_t *encodings;
|
||||
int num_encodings;
|
||||
@ -602,18 +600,6 @@ static void parse_trackentry(struct demuxer *demuxer,
|
||||
if (!strcmp(track->codec_id, MKV_V_MSCOMP)
|
||||
|| !strcmp(track->codec_id, MKV_A_ACM))
|
||||
track->ms_compat = 1;
|
||||
else if (!strcmp(track->codec_id, MKV_S_VOBSUB))
|
||||
track->subtitle_type = 'v';
|
||||
else if (!strcmp(track->codec_id, MKV_S_TEXTSSA)
|
||||
|| !strcmp(track->codec_id, MKV_S_TEXTASS)
|
||||
|| !strcmp(track->codec_id, MKV_S_SSA)
|
||||
|| !strcmp(track->codec_id, MKV_S_ASS))
|
||||
track->subtitle_type = 'a';
|
||||
else if (!strcmp(track->codec_id, MKV_S_TEXTASCII)
|
||||
|| !strcmp(track->codec_id, MKV_S_TEXTUTF8))
|
||||
track->subtitle_type = 't';
|
||||
else if (!strcmp(track->codec_id, MKV_S_PGS))
|
||||
track->subtitle_type = 'p';
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] | + Codec ID: %s\n",
|
||||
track->codec_id);
|
||||
} else
|
||||
@ -1571,9 +1557,28 @@ static int demux_mkv_open_audio(demuxer_t *demuxer, mkv_track_t *track)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char *mkv_sub_tag[][2] = {
|
||||
{ MKV_S_VOBSUB, "dvd_subtitle" },
|
||||
{ MKV_S_TEXTSSA, "ass"},
|
||||
{ MKV_S_TEXTASS, "ass"},
|
||||
{ MKV_S_SSA, "ass"},
|
||||
{ MKV_S_ASS, "ass"},
|
||||
{ MKV_S_TEXTASCII, "subrip"},
|
||||
{ MKV_S_TEXTUTF8, "subrip"},
|
||||
{ MKV_S_PGS, "hdmv_pgs_subtitle"},
|
||||
{0}
|
||||
};
|
||||
|
||||
static int demux_mkv_open_sub(demuxer_t *demuxer, mkv_track_t *track)
|
||||
{
|
||||
if (track->subtitle_type) {
|
||||
const char *subtitle_type = NULL;
|
||||
for (int n = 0; mkv_sub_tag[n][0]; n++) {
|
||||
if (strcmp(track->codec_id, mkv_sub_tag[n][0]) == 0) {
|
||||
subtitle_type = mkv_sub_tag[n][1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (subtitle_type) {
|
||||
bstr in = (bstr){track->private_data, track->private_size};
|
||||
struct sh_stream *gsh = new_sh_stream(demuxer, STREAM_SUB);
|
||||
if (!gsh)
|
||||
@ -1582,7 +1587,7 @@ static int demux_mkv_open_sub(demuxer_t *demuxer, mkv_track_t *track)
|
||||
sh_sub_t *sh = gsh->sub;
|
||||
sh->gsh->demuxer_id = track->tnum;
|
||||
track->sh_sub = sh;
|
||||
sh->type = track->subtitle_type;
|
||||
sh->gsh->codec = subtitle_type;
|
||||
bstr buffer = demux_mkv_decode(track, in, 2);
|
||||
if (buffer.start && buffer.start != track->private_data) {
|
||||
talloc_free(track->private_data);
|
||||
|
@ -523,7 +523,7 @@ static int demux_mpg_read_packet(demuxer_t *demux,int id){
|
||||
|
||||
if(!demux->s_streams[aid]){
|
||||
sh_sub_t *sh = new_sh_sub(demux, aid);
|
||||
if (sh) sh->type = 'v';
|
||||
if (sh) sh->gsh->codec = "dvd_subtitle";
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"==> Found subtitle: %d\n",aid);
|
||||
}
|
||||
|
||||
|
@ -415,11 +415,11 @@ static void ts_add_stream(demuxer_t * demuxer, ES_stream_t *es)
|
||||
if (sh) {
|
||||
switch (es->type) {
|
||||
case SPU_DVB:
|
||||
sh->type = 'b'; break;
|
||||
sh->gsh->codec = "dvb_subtitle"; break;
|
||||
case SPU_DVD:
|
||||
sh->type = 'v'; break;
|
||||
sh->gsh->codec = "dvd_subtitle"; break;
|
||||
case SPU_PGS:
|
||||
sh->type = 'p'; break;
|
||||
sh->gsh->codec = "hdmv_pgs_subtitle"; break;
|
||||
}
|
||||
priv->ts.streams[es->pid].id = priv->last_sid;
|
||||
priv->ts.streams[es->pid].sh = sh;
|
||||
|
@ -171,7 +171,6 @@ typedef struct sh_video {
|
||||
|
||||
typedef struct sh_sub {
|
||||
SH_COMMON
|
||||
char type; // t = text, v = VobSub, a = SSA/ASS, m, x, b, d, p
|
||||
bool active; // after track switch decoder may stay initialized, not active
|
||||
unsigned char *extradata; // extra header data passed from demuxer
|
||||
int extradata_len;
|
||||
@ -189,8 +188,6 @@ struct sh_sub *new_sh_sub_sid_lang(struct demuxer *demuxer, int id, int sid,
|
||||
const char *lang);
|
||||
struct sh_stream *new_sh_stream(struct demuxer *demuxer, enum stream_type type);
|
||||
|
||||
const char *sh_sub_type2str(int type);
|
||||
|
||||
// video.c:
|
||||
int video_read_properties(struct sh_video *sh_video);
|
||||
int video_read_frame(struct sh_video *sh_video, float *frame_time_ptr,
|
||||
|
@ -30,17 +30,36 @@
|
||||
extern const struct sd_functions sd_ass;
|
||||
extern const struct sd_functions sd_lavc;
|
||||
|
||||
bool is_text_sub(const char *t)
|
||||
{
|
||||
return t && (is_ass_sub(t) ||
|
||||
strcmp(t, "text") == 0 ||
|
||||
strcmp(t, "subrip") == 0 ||
|
||||
strcmp(t, "mov_text") == 0);
|
||||
}
|
||||
|
||||
bool is_ass_sub(const char *t)
|
||||
{
|
||||
return t && (strcmp(t, "ass") == 0 ||
|
||||
strcmp(t, "ssa") == 0);
|
||||
}
|
||||
|
||||
bool is_dvd_sub(const char *t)
|
||||
{
|
||||
return t && strcmp(t, "dvd_subtitle") == 0;
|
||||
}
|
||||
|
||||
void sub_init(struct sh_sub *sh, struct osd_state *osd)
|
||||
{
|
||||
struct MPOpts *opts = sh->opts;
|
||||
|
||||
assert(!osd->sh_sub);
|
||||
if (sd_lavc.probe(sh))
|
||||
sh->sd_driver = &sd_lavc;
|
||||
#ifdef CONFIG_ASS
|
||||
if (opts->ass_enabled && is_text_sub(sh->type))
|
||||
if (opts->ass_enabled && sd_ass.probe(sh))
|
||||
sh->sd_driver = &sd_ass;
|
||||
#endif
|
||||
if (strchr("bpxv", sh->type))
|
||||
sh->sd_driver = &sd_lavc;
|
||||
if (sh->sd_driver) {
|
||||
if (sh->sd_driver->init(sh, osd) < 0)
|
||||
return;
|
||||
|
@ -10,10 +10,9 @@ struct sh_sub;
|
||||
struct ass_track;
|
||||
struct MPOpts;
|
||||
|
||||
static inline bool is_text_sub(int type)
|
||||
{
|
||||
return type == 't' || type == 'm' || type == 'a';
|
||||
}
|
||||
bool is_text_sub(const char *t);
|
||||
bool is_ass_sub(const char *t);
|
||||
bool is_dvd_sub(const char *t);
|
||||
|
||||
void sub_decode(struct sh_sub *sh, struct osd_state *osd, void *data,
|
||||
int data_len, double pts, double duration);
|
||||
|
1
sub/sd.h
1
sub/sd.h
@ -4,6 +4,7 @@
|
||||
#include "dec_sub.h"
|
||||
|
||||
struct sd_functions {
|
||||
bool (*probe)(struct sh_sub *sh);
|
||||
int (*init)(struct sh_sub *sh, struct osd_state *osd);
|
||||
void (*decode)(struct sh_sub *sh, struct osd_state *osd,
|
||||
void *data, int data_len, double pts, double duration);
|
||||
|
17
sub/sd_ass.c
17
sub/sd_ass.c
@ -41,6 +41,11 @@ struct sd_ass_priv {
|
||||
bool flush_on_seek;
|
||||
};
|
||||
|
||||
static bool probe(struct sh_sub *sh)
|
||||
{
|
||||
return is_text_sub(sh->gsh->codec);
|
||||
}
|
||||
|
||||
static void free_last_event(ASS_Track *track)
|
||||
{
|
||||
assert(track->n_events > 0);
|
||||
@ -51,13 +56,14 @@ static void free_last_event(ASS_Track *track)
|
||||
static int init(struct sh_sub *sh, struct osd_state *osd)
|
||||
{
|
||||
struct sd_ass_priv *ctx;
|
||||
bool ass = is_ass_sub(sh->gsh->codec);
|
||||
|
||||
if (sh->initialized) {
|
||||
ctx = sh->context;
|
||||
} else {
|
||||
ctx = talloc_zero(NULL, struct sd_ass_priv);
|
||||
sh->context = ctx;
|
||||
if (sh->type == 'a') {
|
||||
if (ass) {
|
||||
ctx->ass_track = ass_new_track(osd->ass_library);
|
||||
if (sh->extradata)
|
||||
ass_process_codec_private(ctx->ass_track, sh->extradata,
|
||||
@ -66,7 +72,7 @@ static int init(struct sh_sub *sh, struct osd_state *osd)
|
||||
ctx->ass_track = mp_ass_default_track(osd->ass_library, sh->opts);
|
||||
}
|
||||
|
||||
ctx->vsfilter_aspect = sh->type == 'a';
|
||||
ctx->vsfilter_aspect = ass;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -77,7 +83,7 @@ static void decode(struct sh_sub *sh, struct osd_state *osd, void *data,
|
||||
struct sd_ass_priv *ctx = sh->context;
|
||||
ASS_Track *track = ctx->ass_track;
|
||||
|
||||
if (sh->type == 'a') { // ssa/ass subs
|
||||
if (is_ass_sub(sh->gsh->codec)) {
|
||||
if (bstr_startswith0((bstr){data, data_len}, "Dialogue: ")) {
|
||||
// broken ffmpeg ASS packet format
|
||||
ctx->flush_on_seek = true;
|
||||
@ -177,6 +183,7 @@ static void uninit(struct sh_sub *sh)
|
||||
}
|
||||
|
||||
const struct sd_functions sd_ass = {
|
||||
.probe = probe,
|
||||
.init = init,
|
||||
.decode = decode,
|
||||
.get_bitmaps = get_bitmaps,
|
||||
@ -199,7 +206,9 @@ struct sh_sub *sd_ass_create_from_track(struct ass_track *track,
|
||||
talloc_set_destructor(sh, sd_ass_track_destructor);
|
||||
*sh = (struct sh_sub) {
|
||||
.opts = opts,
|
||||
.type = 'a',
|
||||
.gsh = talloc_struct(sh, struct sh_stream, {
|
||||
.codec = "ass",
|
||||
}),
|
||||
.sd_driver = &sd_ass,
|
||||
.context = talloc_struct(sh, struct sd_ass_priv, {
|
||||
.ass_track = track,
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "talloc.h"
|
||||
#include "core/mp_msg.h"
|
||||
#include "core/av_common.h"
|
||||
#include "demux/stheader.h"
|
||||
#include "sd.h"
|
||||
#include "dec_sub.h"
|
||||
@ -40,9 +41,24 @@ struct sd_lavc_priv {
|
||||
double endpts;
|
||||
};
|
||||
|
||||
static void guess_resolution(char type, int *w, int *h)
|
||||
static bool probe(struct sh_sub *sh)
|
||||
{
|
||||
if (type == 'v') {
|
||||
enum AVCodecID cid = mp_codec_to_av_codec_id(sh->gsh->codec);
|
||||
// Supported codecs must be known to decode to paletted bitmaps
|
||||
switch (cid) {
|
||||
case AV_CODEC_ID_DVB_SUBTITLE:
|
||||
case AV_CODEC_ID_HDMV_PGS_SUBTITLE:
|
||||
case AV_CODEC_ID_XSUB:
|
||||
case AV_CODEC_ID_DVD_SUBTITLE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void guess_resolution(enum AVCodecID type, int *w, int *h)
|
||||
{
|
||||
if (type == AV_CODEC_ID_DVD_SUBTITLE) {
|
||||
/* XXX Although the video frame is some size, the SPU frame is
|
||||
always maximum size i.e. 720 wide and 576 or 480 high */
|
||||
// For HD files in MKV the VobSub resolution can be higher though,
|
||||
@ -65,17 +81,7 @@ static int init(struct sh_sub *sh, struct osd_state *osd)
|
||||
if (sh->initialized)
|
||||
return 0;
|
||||
struct sd_lavc_priv *priv = talloc_zero(NULL, struct sd_lavc_priv);
|
||||
enum AVCodecID cid = AV_CODEC_ID_NONE;
|
||||
switch (sh->type) {
|
||||
case 'b':
|
||||
cid = AV_CODEC_ID_DVB_SUBTITLE; break;
|
||||
case 'p':
|
||||
cid = AV_CODEC_ID_HDMV_PGS_SUBTITLE; break;
|
||||
case 'x':
|
||||
cid = AV_CODEC_ID_XSUB; break;
|
||||
case 'v':
|
||||
cid = AV_CODEC_ID_DVD_SUBTITLE; break;
|
||||
}
|
||||
enum AVCodecID cid = mp_codec_to_av_codec_id(sh->gsh->codec);
|
||||
AVCodecContext *ctx = NULL;
|
||||
AVCodec *sub_codec = avcodec_find_decoder(cid);
|
||||
if (!sub_codec)
|
||||
@ -194,7 +200,7 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd,
|
||||
talloc_get_size(priv->inbitmaps));
|
||||
int inw = priv->avctx->width;
|
||||
int inh = priv->avctx->height;
|
||||
guess_resolution(sh->type, &inw, &inh);
|
||||
guess_resolution(priv->avctx->codec_id, &inw, &inh);
|
||||
double xscale = (double) (d.w - d.ml - d.mr) / inw;
|
||||
double yscale = (double) (d.h - d.mt - d.mb) / inh;
|
||||
for (int i = 0; i < priv->count; i++) {
|
||||
@ -235,6 +241,7 @@ static void uninit(struct sh_sub *sh)
|
||||
}
|
||||
|
||||
const struct sd_functions sd_lavc = {
|
||||
.probe = probe,
|
||||
.init = init,
|
||||
.decode = decode,
|
||||
.get_bitmaps = get_bitmaps,
|
||||
|
Loading…
Reference in New Issue
Block a user