0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-20 03:52:22 +02: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:
wm4 2013-04-15 21:25:21 +02:00
parent 5ac50f88c9
commit 331982b99c
12 changed files with 91 additions and 92 deletions

View File

@ -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

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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,