[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