summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/mplayer.c10
-rw-r--r--demux/demux.c38
-rw-r--r--demux/demux.h1
-rw-r--r--sub/dec_sub.c60
-rw-r--r--sub/dec_sub.h2
5 files changed, 109 insertions, 2 deletions
diff --git a/core/mplayer.c b/core/mplayer.c
index d9c577b354..3f65573bb5 100644
--- a/core/mplayer.c
+++ b/core/mplayer.c
@@ -2036,12 +2036,22 @@ static void reinit_subs(struct MPContext *mpctx)
if (!sub_is_initialized(dec_sub)) {
int w = mpctx->sh_video ? mpctx->sh_video->disp_w : 0;
int h = mpctx->sh_video ? mpctx->sh_video->disp_h : 0;
+ float fps = mpctx->sh_video ? mpctx->sh_video->fps : 25;
set_dvdsub_fake_extradata(dec_sub, track->demuxer->stream, w, h);
sub_set_video_res(dec_sub, w, h);
+ sub_set_video_fps(dec_sub, fps);
sub_set_ass_renderer(dec_sub, mpctx->osd->ass_library,
mpctx->osd->ass_renderer);
sub_init_from_sh(dec_sub, sh_sub);
+
+ // Don't do this if the file has video/audio streams. Don't do it even
+ // if it has only sub streams, because reading packets will change the
+ // demuxer position.
+ if (!track->preloaded && track->is_external) {
+ demux_seek(track->demuxer, 0, 0, SEEK_ABSOLUTE);
+ track->preloaded = sub_read_all_packets(dec_sub, sh_sub);
+ }
}
mpctx->osd->dec_sub = dec_sub;
diff --git a/demux/demux.c b/demux/demux.c
index d9b41e2c99..23c4a28706 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -40,7 +40,8 @@
#include "audio/format.h"
-#include "libavcodec/avcodec.h"
+#include <libavcodec/avcodec.h>
+
#if MP_INPUT_BUFFER_PADDING_SIZE < FF_INPUT_BUFFER_PADDING_SIZE
#error MP_INPUT_BUFFER_PADDING_SIZE is too small!
#endif
@@ -183,6 +184,41 @@ void free_demux_packet(struct demux_packet *dp)
talloc_free(dp);
}
+static int destroy_avpacket(void *pkt)
+{
+ av_free_packet(pkt);
+ return 0;
+}
+
+struct demux_packet *demux_copy_packet(struct demux_packet *dp)
+{
+ struct demux_packet *new = NULL;
+ // No av_copy_packet() in Libav
+#if LIBAVCODEC_VERSION_MICRO >= 100
+ if (dp->avpacket) {
+ assert(dp->buffer == dp->avpacket->data);
+ assert(dp->len == dp->avpacket->size);
+ AVPacket *newavp = talloc_zero(NULL, AVPacket);
+ talloc_set_destructor(newavp, destroy_avpacket);
+ av_init_packet(newavp);
+ if (av_copy_packet(newavp, dp->avpacket) < 0)
+ abort();
+ new = new_demux_packet_fromdata(newavp->data, newavp->size);
+ new->avpacket = newavp;
+ }
+#endif
+ if (!new) {
+ new = new_demux_packet(dp->len);
+ memcpy(new->buffer, dp->buffer, new->len);
+ }
+ new->pts = dp->pts;
+ new->duration = dp->duration;
+ new->stream_pts = dp->stream_pts;
+ new->pos = dp->pos;
+ new->keyframe = dp->keyframe;
+ return new;
+}
+
static void free_demuxer_stream(struct demux_stream *ds)
{
ds_free_packs(ds);
diff --git a/demux/demux.h b/demux/demux.h
index 9ec6d0c6f0..a82fbea91a 100644
--- a/demux/demux.h
+++ b/demux/demux.h
@@ -291,6 +291,7 @@ struct demux_packet *new_demux_packet_fromdata(void *data, size_t len);
struct demux_packet *new_demux_packet_from(void *data, size_t len);
void resize_demux_packet(struct demux_packet *dp, size_t len);
void free_demux_packet(struct demux_packet *dp);
+struct demux_packet *demux_copy_packet(struct demux_packet *dp);
#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)-1)
diff --git a/sub/dec_sub.c b/sub/dec_sub.c
index b72630470c..187ae5f22c 100644
--- a/sub/dec_sub.c
+++ b/sub/dec_sub.c
@@ -21,7 +21,7 @@
#include <assert.h>
#include "config.h"
-#include "demux/stheader.h"
+#include "demux/demux.h"
#include "sd.h"
#include "sub.h"
#include "dec_sub.h"
@@ -56,10 +56,17 @@ struct dec_sub {
struct MPOpts *opts;
struct sd init_sd;
+ double video_fps;
+
struct sd *sd[MAX_NUM_SD];
int num_sd;
};
+struct packet_list {
+ struct demux_packet **packets;
+ int num_packets;
+};
+
struct dec_sub *sub_create(struct MPOpts *opts)
{
struct dec_sub *sub = talloc_zero(NULL, struct dec_sub);
@@ -102,6 +109,11 @@ void sub_set_video_res(struct dec_sub *sub, int w, int h)
sub->init_sd.sub_video_h = h;
}
+void sub_set_video_fps(struct dec_sub *sub, double fps)
+{
+ sub->video_fps = fps;
+}
+
void sub_set_extradata(struct dec_sub *sub, void *data, int data_len)
{
sub->init_sd.extradata = data_len ? talloc_memdup(sub, data, data_len) : NULL;
@@ -249,6 +261,52 @@ void sub_init_from_sh(struct dec_sub *sub, struct sh_sub *sh)
sh->gsh->codec ? sh->gsh->codec : "<unknown>");
}
+static void add_sub_list(struct dec_sub *sub, struct packet_list *subs)
+{
+ struct sd *sd = sub_get_last_sd(sub);
+ assert(sd);
+
+ sd->no_remove_duplicates = true;
+
+ for (int n = 0; n < subs->num_packets; n++)
+ sub_decode(sub, subs->packets[n]);
+
+ // Hack for broken FFmpeg packet format: make sd_ass keep the subtitle
+ // events on reset(), even if 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->driver->fix_events)
+ sd->driver->fix_events(sd);
+
+ sd->no_remove_duplicates = false;
+}
+
+// Read all packets from the demuxer and decode/add them. Returns false if
+// there are circumstances which makes this not possible.
+bool sub_read_all_packets(struct dec_sub *sub, struct sh_sub *sh)
+{
+ if (!sub_accept_packets_in_advance(sub) || sh->track)
+ return false;
+
+ void *tmp = talloc_new(NULL);
+ struct packet_list subs = {0};
+
+ for (;;) {
+ ds_get_next_pts(sh->ds);
+ struct demux_packet *pkt = ds_get_packet_sub(sh->ds);
+ if (!pkt)
+ break;
+ pkt = demux_copy_packet(pkt);
+ talloc_steal(tmp, pkt);
+ MP_TARRAY_APPEND(tmp, subs.packets, subs.num_packets, pkt);
+ }
+
+ add_sub_list(sub, &subs);
+
+ talloc_free(tmp);
+ return true;
+}
+
bool sub_accept_packets_in_advance(struct dec_sub *sub)
{
// Converters are assumed to always accept packets in advance
diff --git a/sub/dec_sub.h b/sub/dec_sub.h
index 805a87ef5c..c285449f94 100644
--- a/sub/dec_sub.h
+++ b/sub/dec_sub.h
@@ -20,6 +20,7 @@ struct dec_sub *sub_create(struct MPOpts *opts);
void sub_destroy(struct dec_sub *sub);
void sub_set_video_res(struct dec_sub *sub, int w, int h);
+void sub_set_video_fps(struct dec_sub *sub, double fps);
void sub_set_extradata(struct dec_sub *sub, void *data, int data_len);
void sub_set_ass_renderer(struct dec_sub *sub, struct ass_library *ass_library,
struct ass_renderer *ass_renderer);
@@ -27,6 +28,7 @@ void sub_init_from_sh(struct dec_sub *sub, struct sh_sub *sh);
bool sub_is_initialized(struct dec_sub *sub);
+bool sub_read_all_packets(struct dec_sub *sub, struct sh_sub *sh);
bool sub_accept_packets_in_advance(struct dec_sub *sub);
void sub_decode(struct dec_sub *sub, struct demux_packet *packet);
void sub_get_bitmaps(struct dec_sub *sub, struct mp_osd_res dim, double pts,