[FFmpeg-devel] [PATCH 3/4] ffplay: add -subfile option.
Clément Bœsch
ubitux at gmail.com
Tue Nov 27 21:48:57 CET 2012
---
doc/ffplay.texi | 3 ++
ffplay.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 98 insertions(+), 1 deletion(-)
diff --git a/doc/ffplay.texi b/doc/ffplay.texi
index e2bded7..2230f4c 100644
--- a/doc/ffplay.texi
+++ b/doc/ffplay.texi
@@ -85,6 +85,9 @@ also sources and sinks).
@item -i @var{input_file}
Read @var{input_file}.
+
+ at item -subfile @var{file}
+Load external subtitle file.
@end table
@section Advanced options
diff --git a/ffplay.c b/ffplay.c
index 6013cd1..35b99fd 100644
--- a/ffplay.c
+++ b/ffplay.c
@@ -269,6 +269,7 @@ typedef struct VideoState {
static AVInputFormat *file_iformat;
static const char *input_filename;
static const char *window_title;
+static const char *subtitles_filename;
static int fs_screen_width;
static int fs_screen_height;
static int screen_width = 0;
@@ -383,6 +384,77 @@ static void uninit_text_sub_rendering(void)
ass_library_done(libass_library);
}
+static int load_subtitle_file(const char *subfile)
+{
+ int ret, sid;
+ AVFormatContext *fmt = NULL;
+ AVCodecContext *dec_ctx = NULL;
+ AVCodec *dec = NULL;
+ AVStream *st;
+ AVPacket pkt;
+
+ /* Open subtitle file */
+ ret = avformat_open_input(&fmt, subfile, NULL, NULL);
+ if (ret < 0)
+ goto end;
+ ret = avformat_find_stream_info(fmt, NULL);
+ if (ret < 0)
+ goto end;
+
+ /* Locate subtitle stream */
+ ret = av_find_best_stream(fmt, AVMEDIA_TYPE_SUBTITLE, -1, -1, NULL, 0);
+ if (ret < 0)
+ goto end;
+ sid = ret;
+ st = fmt->streams[sid];
+
+ /* TODO: seek to honor start_time */
+
+ /* Open decoder */
+ dec_ctx = st->codec;
+ dec = avcodec_find_decoder(dec_ctx->codec_id);
+ if (!dec) {
+ av_log(NULL, AV_LOG_ERROR, "Failed to find subtitle codec\n");
+ return AVERROR(EINVAL);
+ }
+ ret = avcodec_open2(dec_ctx, dec, NULL);
+ if (ret < 0)
+ goto end;
+
+ /* Decode subtitles and push them into the renderer (libass) */
+ if (dec_ctx->subtitle_header)
+ ass_process_codec_private(libass_track,
+ dec_ctx->subtitle_header,
+ dec_ctx->subtitle_header_size);
+ av_init_packet(&pkt);
+ pkt.data = NULL;
+ pkt.size = 0;
+ while (av_read_frame(fmt, &pkt) >= 0) {
+ int i, got_subtitle;
+ AVSubtitle sub;
+
+ if (pkt.stream_index == sid) {
+ ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_subtitle, &pkt);
+ if (ret < 0 || !got_subtitle)
+ break;
+ for (i = 0; i < sub.num_rects; i++) {
+ char *ass_line = sub.rects[i]->ass;
+ ass_process_data(libass_track, ass_line, strlen(ass_line));
+ }
+ }
+ av_free_packet(&pkt);
+ avsubtitle_free(&sub);
+ }
+
+end:
+ if (fmt) avformat_close_input(&fmt);
+ if (dec_ctx) avcodec_close(dec_ctx);
+ if (ret < 0)
+ print_error(subfile, ret);
+ else
+ av_log(NULL, AV_LOG_INFO, "Subtitle %s loaded\n", subfile);
+ return ret;
+}
#else
static int init_text_sub_rendering(void) { return 0; }
static void uninit_text_sub_rendering(void) { }
@@ -886,6 +958,9 @@ static void video_image_display(VideoState *is)
vp = &is->pictq[is->pictq_rindex];
if (vp->bmp) {
+ if (subtitles_filename)
+ blend_text_subtitles(vp);
+ else
if (is->subtitle_st) {
if (is->subpq_size > 0) {
sp = &is->subpq[is->subpq_rindex];
@@ -2759,17 +2834,23 @@ static int read_thread(void *arg)
infinite_buffer = 1;
#if TEXT_SUBTITLES_RENDERING
- if (is->video_st && is->subtitle_st) {
+ if (is->video_st && (is->subtitle_st || subtitles_filename)) {
ret = ff_draw_init(&subrender_draw, AV_PIX_FMT_YUV420P, 0);
if (ret < 0)
return ret;
ass_set_frame_size(libass_renderer,
is->video_st->codec->width,
is->video_st->codec->height);
+ if (subtitles_filename) {
+ ret = load_subtitle_file(subtitles_filename);
+ if (ret < 0)
+ goto fail;
+ } else {
if (is->subtitle_st->codec->subtitle_header)
ass_process_codec_private(libass_track,
is->subtitle_st->codec->subtitle_header,
is->subtitle_st->codec->subtitle_header_size);
+ }
}
#endif
@@ -3294,6 +3375,18 @@ static int opt_codec(void *o, const char *opt, const char *arg)
return 0;
}
+static int opt_subfile(void *o, const char *opt, const char *arg)
+{
+#if TEXT_SUBTITLES_RENDERING
+ subtitles_filename = arg;
+ return 0;
+#else
+ av_log(NULL, AV_LOG_ERROR, "You need to build FFmpeg with libass and "
+ "libavfilter support for text subtitles rendering.\n");
+ return AVERROR(EINVAL);
+#endif
+}
+
static int dummy;
static const OptionDef options[] = {
@@ -3340,6 +3433,7 @@ static const OptionDef options[] = {
{ "default", HAS_ARG | OPT_AUDIO | OPT_VIDEO | OPT_EXPERT, { .func_arg = opt_default }, "generic catch all option", "" },
{ "i", OPT_BOOL, { &dummy}, "read specified file", "input_file"},
{ "codec", HAS_ARG, { .func_arg = opt_codec}, "force decoder", "decoder" },
+ { "subfile", HAS_ARG, { .func_arg = opt_subfile }, "set subtitles file", "file" },
{ NULL, },
};
--
1.8.0.1
More information about the ffmpeg-devel
mailing list