mirror of
https://github.com/mpv-player/mpv
synced 2024-08-24 07:21:49 +02:00
subreader: turn into actual demuxer
subreader.c (before this commit renamed to demux_subreader.c) was special cased to the -sub option. The plan is using the normal demuxer codepath for all subtitle formats (so we can prefer libavformat demuxers for most formats). There are some subtle changes. The probe size is restricted to 32 KB (instead of unlimitted + giving up after 100 lines of input). For formats like MicroDVD, the video FPS isn't used anymore, because it's not available on the subtitle demuxer level. Instead, hardcode it to 23.976 FPS (libavformat seems to do the same). The user can probably still use -sub-fps to fix the timing. Checking the file extension for ".utf"/".utf8"/".utf-8" is simply removed (seems worthless, was in the way, and I've never seen this anywhere).
This commit is contained in:
parent
b37147744e
commit
98388c0c07
@ -71,7 +71,6 @@
|
||||
#include "core/mplayer.h"
|
||||
#include "core/m_property.h"
|
||||
|
||||
#include "demux/subreader.h"
|
||||
#include "sub/find_subfiles.h"
|
||||
#include "sub/dec_sub.h"
|
||||
#include "sub/sd.h"
|
||||
@ -1044,7 +1043,6 @@ struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename,
|
||||
{
|
||||
struct MPOpts *opts = &mpctx->opts;
|
||||
struct ass_track *asst = NULL;
|
||||
sub_data *subd = NULL;
|
||||
|
||||
if (filename == NULL)
|
||||
return NULL;
|
||||
@ -1055,17 +1053,14 @@ struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename,
|
||||
// the weird special-cases.
|
||||
#ifdef CONFIG_ASS
|
||||
asst = mp_ass_read_stream(mpctx->ass_library, filename, opts->sub_cp);
|
||||
if (!asst)
|
||||
subd = sub_read_file(filename, fps, &mpctx->opts);
|
||||
if (asst || subd) {
|
||||
if (asst) {
|
||||
struct demuxer *d = new_sub_pseudo_demuxer(opts);
|
||||
assert(d->num_streams == 1);
|
||||
struct sh_stream *s = d->streams[0];
|
||||
assert(s->type == STREAM_SUB);
|
||||
|
||||
s->codec = asst ? "ass" : subd->codec;
|
||||
s->codec = "ass";
|
||||
s->sub->track = asst;
|
||||
s->sub->sub_data = subd;
|
||||
|
||||
struct sh_sub **pptr = talloc(d, struct sh_sub*);
|
||||
*pptr = s->sub;
|
||||
|
@ -147,7 +147,6 @@ typedef struct MPOpts {
|
||||
// subreader.c
|
||||
int suboverlap_enabled;
|
||||
char *sub_cp;
|
||||
int sub_no_text_pp;
|
||||
|
||||
char *audio_stream;
|
||||
int audio_stream_cache;
|
||||
|
@ -68,6 +68,7 @@ extern const demuxer_desc_t demuxer_desc_mpeg4_es;
|
||||
extern const demuxer_desc_t demuxer_desc_h264_es;
|
||||
extern const demuxer_desc_t demuxer_desc_mpeg_ts;
|
||||
extern const demuxer_desc_t demuxer_desc_sub;
|
||||
extern const demuxer_desc_t demuxer_desc_subreader;
|
||||
|
||||
/* 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
|
||||
@ -83,6 +84,7 @@ const demuxer_desc_t *const demuxer_list[] = {
|
||||
#endif
|
||||
&demuxer_desc_matroska,
|
||||
&demuxer_desc_lavf,
|
||||
&demuxer_desc_subreader,
|
||||
&demuxer_desc_avi,
|
||||
&demuxer_desc_asf,
|
||||
#ifdef CONFIG_MNG
|
||||
|
@ -71,6 +71,7 @@ enum demuxer_type {
|
||||
DEMUXER_TYPE_MNG,
|
||||
DEMUXER_TYPE_EDL,
|
||||
DEMUXER_TYPE_CUE,
|
||||
DEMUXER_TYPE_SUBREADER,
|
||||
|
||||
/* Values after this are for internal use and can not be selected
|
||||
* as demuxer type by the user (-demuxer option). */
|
||||
|
@ -28,14 +28,15 @@
|
||||
#include <dirent.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <libavutil/common.h>
|
||||
#include <libavutil/avstring.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "core/mp_msg.h"
|
||||
#include "subreader.h"
|
||||
#include "core/mp_common.h"
|
||||
#include "core/options.h"
|
||||
#include "stream/stream.h"
|
||||
#include "libavutil/common.h"
|
||||
#include "libavutil/avstring.h"
|
||||
#include "demux/demux.h"
|
||||
|
||||
#ifdef CONFIG_ENCA
|
||||
#include <enca.h>
|
||||
@ -47,6 +48,54 @@
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
|
||||
// subtitle formats
|
||||
#define SUB_INVALID -1
|
||||
#define SUB_MICRODVD 0
|
||||
#define SUB_SUBRIP 1
|
||||
#define SUB_SUBVIEWER 2
|
||||
#define SUB_SAMI 3
|
||||
#define SUB_VPLAYER 4
|
||||
#define SUB_RT 5
|
||||
#define SUB_SSA 6
|
||||
#define SUB_PJS 7
|
||||
#define SUB_MPSUB 8
|
||||
#define SUB_AQTITLE 9
|
||||
#define SUB_SUBVIEWER2 10
|
||||
#define SUB_SUBRIP09 11
|
||||
#define SUB_JACOSUB 12
|
||||
#define SUB_MPL2 13
|
||||
|
||||
#define SUB_MAX_TEXT 12
|
||||
#define SUB_ALIGNMENT_BOTTOMLEFT 1
|
||||
#define SUB_ALIGNMENT_BOTTOMCENTER 2
|
||||
#define SUB_ALIGNMENT_BOTTOMRIGHT 3
|
||||
#define SUB_ALIGNMENT_MIDDLELEFT 4
|
||||
#define SUB_ALIGNMENT_MIDDLECENTER 5
|
||||
#define SUB_ALIGNMENT_MIDDLERIGHT 6
|
||||
#define SUB_ALIGNMENT_TOPLEFT 7
|
||||
#define SUB_ALIGNMENT_TOPCENTER 8
|
||||
#define SUB_ALIGNMENT_TOPRIGHT 9
|
||||
|
||||
typedef struct subtitle {
|
||||
|
||||
int lines;
|
||||
|
||||
unsigned long start;
|
||||
unsigned long end;
|
||||
|
||||
char *text[SUB_MAX_TEXT];
|
||||
unsigned char alignment;
|
||||
} subtitle;
|
||||
|
||||
typedef struct sub_data {
|
||||
const char *codec;
|
||||
subtitle *subtitles;
|
||||
int sub_uses_time;
|
||||
int sub_num; // number of subtitle structs
|
||||
int sub_errs;
|
||||
double fallback_fps;
|
||||
} sub_data;
|
||||
|
||||
// Parameter struct for the format-specific readline functions
|
||||
struct readline_args {
|
||||
int utf16;
|
||||
@ -58,6 +107,8 @@ struct readline_args {
|
||||
float mpsub_position;
|
||||
int sub_slacktime;
|
||||
|
||||
int uses_time;
|
||||
|
||||
/*
|
||||
Some subtitling formats, namely AQT and Subrip09, define the end of a
|
||||
subtitle as the beginning of the following. Since currently we read one
|
||||
@ -171,7 +222,7 @@ static subtitle *sub_read_line_sami(stream_t* st, subtitle *current,
|
||||
sami_add_line(current, text, &p);
|
||||
s += 4;
|
||||
}
|
||||
else if ((*s == '{') && !args->opts->sub_no_text_pp) { state = 5; ++s; continue; }
|
||||
else if ((*s == '{')) { state = 5; ++s; continue; }
|
||||
else if (*s == '<') { state = 4; }
|
||||
else if (!strncasecmp (s, " ", 6)) { *p++ = ' '; s += 6; }
|
||||
else if (*s == '\t') { *p++ = ' '; s++; }
|
||||
@ -197,7 +248,7 @@ static subtitle *sub_read_line_sami(stream_t* st, subtitle *current,
|
||||
if (s) { s++; state = 3; continue; }
|
||||
break;
|
||||
case 5: /* get rid of {...} text, but read the alignment code */
|
||||
if ((*s == '\\') && (*(s + 1) == 'a') && !args->opts->sub_no_text_pp) {
|
||||
if ((*s == '\\') && (*(s + 1) == 'a')) {
|
||||
if (stristr(s, "\\a1") != NULL) {
|
||||
current->alignment = SUB_ALIGNMENT_BOTTOMLEFT;
|
||||
s = s + 3;
|
||||
@ -1130,6 +1181,7 @@ struct subreader {
|
||||
void (*post)(subtitle *dest);
|
||||
const char *name;
|
||||
const char *codec_name;
|
||||
struct readline_args args;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ENCA
|
||||
@ -1192,16 +1244,9 @@ static const char* guess_cp(stream_t *st, const char *preferred_language, const
|
||||
#undef MAX_GUESS_BUFFER_SIZE
|
||||
#endif
|
||||
|
||||
static int sub_destroy(void *ptr);
|
||||
|
||||
sub_data* sub_read_file(char *filename, float fps, struct MPOpts *opts)
|
||||
static bool subreader_autodetect(stream_t *fd, struct MPOpts *opts,
|
||||
struct subreader *out)
|
||||
{
|
||||
int utf16;
|
||||
stream_t* fd;
|
||||
int n_max, i, j;
|
||||
subtitle *first, *sub, *return_sub, *alloced_sub = NULL;
|
||||
sub_data *subt_data;
|
||||
int uses_time = 0, sub_num = 0, sub_errs = 0;
|
||||
static const struct subreader sr[]=
|
||||
{
|
||||
{ sub_read_line_microdvd, NULL, "microdvd", "microdvd" },
|
||||
@ -1221,42 +1266,46 @@ sub_data* sub_read_file(char *filename, float fps, struct MPOpts *opts)
|
||||
};
|
||||
const struct subreader *srp;
|
||||
|
||||
if(filename==NULL) return NULL; //qnx segfault
|
||||
fd=open_stream (filename, NULL, NULL); if (!fd) return NULL;
|
||||
|
||||
int sub_format = SUB_INVALID;
|
||||
int utf16;
|
||||
int uses_time = 0;
|
||||
for (utf16 = 0; sub_format == SUB_INVALID && utf16 < 3; utf16++) {
|
||||
sub_format=sub_autodetect (fd, &uses_time, utf16);
|
||||
stream_seek(fd,0);
|
||||
}
|
||||
utf16--;
|
||||
|
||||
struct readline_args args = {utf16, opts};
|
||||
args.sub_slacktime = 20000; //20 sec
|
||||
args.mpsub_multiplier = (uses_time ? 100.0 : 1.0);
|
||||
|
||||
if (sub_format==SUB_INVALID) {
|
||||
mp_msg(MSGT_SUBREADER,MSGL_WARN,"SUB: Could not determine file format\n");
|
||||
free_stream(fd);
|
||||
return NULL;
|
||||
mp_msg(MSGT_SUBREADER,MSGL_V,"SUB: Could not determine file format\n");
|
||||
return false;
|
||||
}
|
||||
srp=sr+sub_format;
|
||||
mp_msg(MSGT_SUBREADER, MSGL_V, "SUB: Detected subtitle file format: %s\n", srp->name);
|
||||
|
||||
*out = *srp;
|
||||
out->args = (struct readline_args) {
|
||||
.utf16 = utf16,
|
||||
.opts = opts,
|
||||
.sub_slacktime = 20000, //20 sec
|
||||
.mpsub_multiplier = (uses_time ? 100.0 : 1.0),
|
||||
.uses_time = uses_time,
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static sub_data* sub_read_file(stream_t *fd, struct subreader *srp)
|
||||
{
|
||||
struct MPOpts *opts = fd->opts;
|
||||
float fps = 23.976;
|
||||
int n_max, i, j;
|
||||
subtitle *first, *sub, *return_sub, *alloced_sub = NULL;
|
||||
sub_data *subt_data;
|
||||
int sub_num = 0, sub_errs = 0;
|
||||
struct readline_args args = srp->args;
|
||||
|
||||
#ifdef CONFIG_ICONV
|
||||
iconv_t icdsc = (iconv_t)(-1);
|
||||
{
|
||||
int l,k;
|
||||
k = -1;
|
||||
if ((l=strlen(filename))>4){
|
||||
char *exts[] = {".utf", ".utf8", ".utf-8" };
|
||||
for (k=3;--k>=0;)
|
||||
if (l >= strlen(exts[k]) && !strcasecmp(filename+(l - strlen(exts[k])), exts[k])){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (k<0) icdsc = subcp_open(fd, opts->sub_cp);
|
||||
}
|
||||
iconv_t icdsc = subcp_open(fd, opts->sub_cp);
|
||||
#endif
|
||||
|
||||
sub_num=0;n_max=32;
|
||||
@ -1287,11 +1336,10 @@ sub_data* sub_read_file(char *filename, float fps, struct MPOpts *opts)
|
||||
#endif
|
||||
free(first);
|
||||
free(alloced_sub);
|
||||
free_stream(fd);
|
||||
return NULL;
|
||||
}
|
||||
// Apply any post processing that needs recoding first
|
||||
if ((sub!=ERR) && !args.opts->sub_no_text_pp && srp->post) srp->post(sub);
|
||||
if ((sub!=ERR) && srp->post) srp->post(sub);
|
||||
if(!sub_num || (first[sub_num - 1].start <= sub->start)){
|
||||
first[sub_num].start = sub->start;
|
||||
first[sub_num].end = sub->end;
|
||||
@ -1333,8 +1381,6 @@ sub_data* sub_read_file(char *filename, float fps, struct MPOpts *opts)
|
||||
if(sub==ERR) ++sub_errs; else ++sub_num; // Error vs. Valid
|
||||
}
|
||||
|
||||
free_stream(fd);
|
||||
|
||||
#ifdef CONFIG_ICONV
|
||||
subcp_close(icdsc);
|
||||
#endif
|
||||
@ -1349,15 +1395,13 @@ sub_data* sub_read_file(char *filename, float fps, struct MPOpts *opts)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
adjust_subs_time(first, 6.0, fps, opts->sub_fps, 1, sub_num, uses_time);/*~6 secs AST*/
|
||||
adjust_subs_time(first, 6.0, fps, opts->sub_fps, 1, sub_num, args.uses_time);/*~6 secs AST*/
|
||||
return_sub = first;
|
||||
|
||||
if (return_sub == NULL) return NULL;
|
||||
subt_data = talloc_zero(NULL, sub_data);
|
||||
talloc_set_destructor(subt_data, sub_destroy);
|
||||
subt_data->codec = srp->codec_name ? srp->codec_name : "text";
|
||||
subt_data->filename = strdup(filename);
|
||||
subt_data->sub_uses_time = uses_time;
|
||||
subt_data->sub_uses_time = args.uses_time;
|
||||
subt_data->sub_num = sub_num;
|
||||
subt_data->sub_errs = sub_errs;
|
||||
subt_data->subtitles = return_sub;
|
||||
@ -1365,14 +1409,145 @@ sub_data* sub_read_file(char *filename, float fps, struct MPOpts *opts)
|
||||
return subt_data;
|
||||
}
|
||||
|
||||
static int sub_destroy(void *ptr)
|
||||
static void subdata_free(sub_data *subd)
|
||||
{
|
||||
sub_data *subd = ptr;
|
||||
int i, j;
|
||||
for (i = 0; i < subd->sub_num; i++)
|
||||
for (j = 0; j < subd->subtitles[i].lines; j++)
|
||||
free( subd->subtitles[i].text[j] );
|
||||
free( subd->subtitles );
|
||||
free( subd->filename );
|
||||
return 0;
|
||||
talloc_free(subd);
|
||||
}
|
||||
|
||||
struct priv {
|
||||
struct demux_packet **pkts;
|
||||
int num_pkts;
|
||||
int current;
|
||||
struct sh_stream *sh;
|
||||
};
|
||||
|
||||
static void add_sub_data(struct demuxer *demuxer, struct sub_data *subdata)
|
||||
{
|
||||
struct priv *priv = demuxer->priv;
|
||||
|
||||
for (int i = 0; i < subdata->sub_num; i++) {
|
||||
subtitle *st = &subdata->subtitles[i];
|
||||
// subdata is in 10 ms ticks, pts is in seconds
|
||||
double t = subdata->sub_uses_time ? 0.01 : (1 / subdata->fallback_fps);
|
||||
|
||||
int len = 0;
|
||||
for (int j = 0; j < st->lines; j++)
|
||||
len += st->text[j] ? strlen(st->text[j]) : 0;
|
||||
|
||||
len += 2 * st->lines; // '\N', including the one after the last line
|
||||
len += 6; // {\anX}
|
||||
len += 1; // '\0'
|
||||
|
||||
char *data = talloc_array(NULL, char, len);
|
||||
|
||||
char *p = data;
|
||||
char *end = p + len;
|
||||
|
||||
if (st->alignment)
|
||||
p += snprintf(p, end - p, "{\\an%d}", st->alignment);
|
||||
|
||||
for (int j = 0; j < st->lines; j++)
|
||||
p += snprintf(p, end - p, "%s\\N", st->text[j]);
|
||||
|
||||
if (st->lines > 0)
|
||||
p -= 2; // remove last "\N"
|
||||
*p = 0;
|
||||
|
||||
struct demux_packet *pkt = talloc_ptrtype(priv, pkt);
|
||||
*pkt = (struct demux_packet) {
|
||||
.pts = st->start * t,
|
||||
.duration = (st->end - st->start) * t,
|
||||
.buffer = talloc_steal(pkt, data),
|
||||
.len = strlen(data),
|
||||
};
|
||||
|
||||
MP_TARRAY_APPEND(priv, priv->pkts, priv->num_pkts, pkt);
|
||||
}
|
||||
}
|
||||
|
||||
static struct stream *read_probe_stream(struct stream *s, int max)
|
||||
{
|
||||
// Very roundabout, but only needed for initial probing.
|
||||
bstr probe = stream_peek(s, max);
|
||||
return open_memory_stream(probe.start, probe.len);
|
||||
}
|
||||
|
||||
#define PROBE_SIZE FFMIN(32 * 1024, STREAM_MAX_BUFFER_SIZE)
|
||||
|
||||
static int d_check_file(struct demuxer *demuxer)
|
||||
{
|
||||
struct stream *ps = read_probe_stream(demuxer->stream, PROBE_SIZE);
|
||||
|
||||
struct subreader sr;
|
||||
bool res = subreader_autodetect(ps, demuxer->opts, &sr);
|
||||
|
||||
free_stream(ps);
|
||||
|
||||
if (!res)
|
||||
return 0;
|
||||
|
||||
sub_data *sd = sub_read_file(demuxer->stream, &sr);
|
||||
if (!sd)
|
||||
return 0;
|
||||
|
||||
struct priv *p = talloc_zero(demuxer, struct priv);
|
||||
demuxer->priv = p;
|
||||
|
||||
p->sh = new_sh_stream(demuxer, STREAM_SUB);
|
||||
p->sh->codec = sd->codec;
|
||||
|
||||
add_sub_data(demuxer, sd);
|
||||
subdata_free(sd);
|
||||
|
||||
demuxer->accurate_seek = true;
|
||||
|
||||
return DEMUXER_TYPE_SUBREADER;
|
||||
}
|
||||
|
||||
static int d_fill_buffer(struct demuxer *demuxer, struct demux_stream *ds)
|
||||
{
|
||||
struct priv *p = demuxer->priv;
|
||||
struct demux_packet *dp = demux_packet_list_fill(p->pkts, p->num_pkts,
|
||||
&p->current);
|
||||
return demuxer_add_packet(demuxer, p->sh, dp);
|
||||
}
|
||||
|
||||
static void d_seek(struct demuxer *demuxer, float secs, float audio_delay,
|
||||
int flags)
|
||||
{
|
||||
struct priv *p = demuxer->priv;
|
||||
demux_packet_list_seek(p->pkts, p->num_pkts, &p->current, secs, flags);
|
||||
}
|
||||
|
||||
static int d_control(struct demuxer *demuxer, int cmd, void *arg)
|
||||
{
|
||||
struct priv *p = demuxer->priv;
|
||||
switch (cmd) {
|
||||
case DEMUXER_CTRL_CORRECT_PTS:
|
||||
return DEMUXER_CTRL_OK;
|
||||
case DEMUXER_CTRL_GET_TIME_LENGTH:
|
||||
*((double *) arg) = demux_packet_list_duration(p->pkts, p->num_pkts);
|
||||
return DEMUXER_CTRL_OK;
|
||||
default:
|
||||
return DEMUXER_CTRL_NOTIMPL;
|
||||
}
|
||||
}
|
||||
|
||||
const struct demuxer_desc demuxer_desc_subreader = {
|
||||
.info = "Deprecated MPlayer subtitle reader",
|
||||
.name = "subreader",
|
||||
.shortdesc = "Deprecated Subreader",
|
||||
.author = "",
|
||||
.comment = "",
|
||||
.type = DEMUXER_TYPE_SUBREADER,
|
||||
.safe_check = 1,
|
||||
.check_file = d_check_file,
|
||||
.fill_buffer = d_fill_buffer,
|
||||
.seek = d_seek,
|
||||
.control = d_control,
|
||||
};
|
||||
|
@ -164,7 +164,6 @@ typedef struct sh_sub {
|
||||
unsigned char *extradata; // extra header data passed from demuxer
|
||||
int extradata_len;
|
||||
struct ass_track *track; // loaded by libass
|
||||
struct sub_data *sub_data; // loaded by subreader.c
|
||||
struct dec_sub *dec_sub; // decoder context
|
||||
} sh_sub_t;
|
||||
|
||||
|
@ -1,79 +0,0 @@
|
||||
/*
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* MPlayer 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.
|
||||
*
|
||||
* MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPLAYER_SUBREADER_H
|
||||
#define MPLAYER_SUBREADER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
// subtitle formats
|
||||
#define SUB_INVALID -1
|
||||
#define SUB_MICRODVD 0
|
||||
#define SUB_SUBRIP 1
|
||||
#define SUB_SUBVIEWER 2
|
||||
#define SUB_SAMI 3
|
||||
#define SUB_VPLAYER 4
|
||||
#define SUB_RT 5
|
||||
#define SUB_SSA 6
|
||||
#define SUB_PJS 7
|
||||
#define SUB_MPSUB 8
|
||||
#define SUB_AQTITLE 9
|
||||
#define SUB_SUBVIEWER2 10
|
||||
#define SUB_SUBRIP09 11
|
||||
#define SUB_JACOSUB 12
|
||||
#define SUB_MPL2 13
|
||||
|
||||
#define SUB_MAX_TEXT 12
|
||||
#define SUB_ALIGNMENT_BOTTOMLEFT 1
|
||||
#define SUB_ALIGNMENT_BOTTOMCENTER 2
|
||||
#define SUB_ALIGNMENT_BOTTOMRIGHT 3
|
||||
#define SUB_ALIGNMENT_MIDDLELEFT 4
|
||||
#define SUB_ALIGNMENT_MIDDLECENTER 5
|
||||
#define SUB_ALIGNMENT_MIDDLERIGHT 6
|
||||
#define SUB_ALIGNMENT_TOPLEFT 7
|
||||
#define SUB_ALIGNMENT_TOPCENTER 8
|
||||
#define SUB_ALIGNMENT_TOPRIGHT 9
|
||||
|
||||
typedef struct subtitle {
|
||||
|
||||
int lines;
|
||||
|
||||
unsigned long start;
|
||||
unsigned long end;
|
||||
|
||||
char *text[SUB_MAX_TEXT];
|
||||
unsigned char alignment;
|
||||
} subtitle;
|
||||
|
||||
typedef struct sub_data {
|
||||
const char *codec;
|
||||
subtitle *subtitles;
|
||||
char *filename;
|
||||
int sub_uses_time;
|
||||
int sub_num; // number of subtitle structs
|
||||
int sub_errs;
|
||||
double fallback_fps;
|
||||
} sub_data;
|
||||
|
||||
struct MPOpts;
|
||||
sub_data* sub_read_file (char *filename, float pts, struct MPOpts *opts);
|
||||
|
||||
#endif /* MPLAYER_SUBREADER_H */
|
@ -25,7 +25,6 @@
|
||||
#include "sd.h"
|
||||
#include "sub.h"
|
||||
#include "dec_sub.h"
|
||||
#include "demux/subreader.h"
|
||||
#include "core/options.h"
|
||||
#include "core/mp_msg.h"
|
||||
|
||||
@ -138,68 +137,6 @@ static void print_chain(struct dec_sub *sub)
|
||||
mp_msg(MSGT_OSD, MSGL_V, "\n");
|
||||
}
|
||||
|
||||
// Subtitles read with subreader.c
|
||||
static void read_sub_data(struct dec_sub *sub, struct sub_data *subdata)
|
||||
{
|
||||
assert(sub_accept_packets_in_advance(sub));
|
||||
char *temp = NULL;
|
||||
|
||||
struct sd *sd = sub_get_last_sd(sub);
|
||||
|
||||
sd->no_remove_duplicates = true;
|
||||
|
||||
for (int i = 0; i < subdata->sub_num; i++) {
|
||||
subtitle *st = &subdata->subtitles[i];
|
||||
// subdata is in 10 ms ticks, pts is in seconds
|
||||
double t = subdata->sub_uses_time ? 0.01 : (1 / subdata->fallback_fps);
|
||||
|
||||
int len = 0;
|
||||
for (int j = 0; j < st->lines; j++)
|
||||
len += st->text[j] ? strlen(st->text[j]) : 0;
|
||||
|
||||
len += 2 * st->lines; // '\N', including the one after the last line
|
||||
len += 6; // {\anX}
|
||||
len += 1; // '\0'
|
||||
|
||||
if (talloc_get_size(temp) < len) {
|
||||
talloc_free(temp);
|
||||
temp = talloc_array(NULL, char, len);
|
||||
}
|
||||
|
||||
char *p = temp;
|
||||
char *end = p + len;
|
||||
|
||||
if (st->alignment)
|
||||
p += snprintf(p, end - p, "{\\an%d}", st->alignment);
|
||||
|
||||
for (int j = 0; j < st->lines; j++)
|
||||
p += snprintf(p, end - p, "%s\\N", st->text[j]);
|
||||
|
||||
if (st->lines > 0)
|
||||
p -= 2; // remove last "\N"
|
||||
*p = 0;
|
||||
|
||||
struct demux_packet pkt = {0};
|
||||
pkt.pts = st->start * t;
|
||||
pkt.duration = (st->end - st->start) * t;
|
||||
pkt.buffer = temp;
|
||||
pkt.len = strlen(temp);
|
||||
|
||||
sub_decode(sub, &pkt);
|
||||
}
|
||||
|
||||
// Hack for broken FFmpeg packet format: make sd_ass keep the subtitle
|
||||
// events on reset(), even though broken FFmpeg ASS packets were received
|
||||
// (from sd_lavc_conv.c). Normally, these events are removed on seek/reset,
|
||||
// but this is obviously unwanted in this case.
|
||||
if (sd && sd->driver->fix_events)
|
||||
sd->driver->fix_events(sd);
|
||||
|
||||
sd->no_remove_duplicates = false;
|
||||
|
||||
talloc_free(temp);
|
||||
}
|
||||
|
||||
static int sub_init_decoder(struct dec_sub *sub, struct sd *sd)
|
||||
{
|
||||
sd->driver = NULL;
|
||||
@ -242,8 +179,6 @@ void sub_init_from_sh(struct dec_sub *sub, struct sh_sub *sh)
|
||||
// Try adding new converters until a decoder is reached
|
||||
if (sd->driver->get_bitmaps || sd->driver->get_text) {
|
||||
print_chain(sub);
|
||||
if (sh->sub_data)
|
||||
read_sub_data(sub, sh->sub_data);
|
||||
return;
|
||||
}
|
||||
init_sd = (struct sd) {
|
||||
|
Loading…
Reference in New Issue
Block a user