[FFmpeg-devel] [PATCH] ffprobe: decode and dump subtitles.

Nicolas George nicolas.george at normalesup.org
Tue Jul 24 18:35:56 CEST 2012


Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
---
 doc/ffprobe.texi |    2 +-
 doc/ffprobe.xsd  |   33 ++++++++++++++++++++++++-
 ffprobe.c        |   70 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 98 insertions(+), 7 deletions(-)

diff --git a/doc/ffprobe.texi b/doc/ffprobe.texi
index cbe48a7..2fa2cdf 100644
--- a/doc/ffprobe.texi
+++ b/doc/ffprobe.texi
@@ -130,7 +130,7 @@ Show information about each frame contained in the input multimedia
 stream.
 
 The information for each single frame is printed within a dedicated
-section with name "FRAME".
+section with name "FRAME", or "SUBTITLE" for subtitles.
 
 @item -show_streams
 Show information about each media stream contained in the input
diff --git a/doc/ffprobe.xsd b/doc/ffprobe.xsd
index 3a4a8cc..254c801 100644
--- a/doc/ffprobe.xsd
+++ b/doc/ffprobe.xsd
@@ -26,7 +26,10 @@
 
     <xsd:complexType name="framesType">
         <xsd:sequence>
-            <xsd:element name="frame" type="ffprobe:frameType" minOccurs="0" maxOccurs="unbounded"/>
+            <xsd:choice minOccurs="0" maxOccurs="unbounded">
+                <xsd:element name="frame" type="ffprobe:frameType" minOccurs="0" maxOccurs="unbounded"/>
+                <xsd:element name="subtitle" type="ffprobe:subtitleType" minOccurs="0" maxOccurs="unbounded"/>
+            </xsd:choice>
         </xsd:sequence>
     </xsd:complexType>
 
@@ -77,6 +80,34 @@
       <xsd:attribute name="reference"              type="xsd:int"   />
     </xsd:complexType>
 
+    <xsd:complexType name="subtitleType">
+        <xsd:sequence>
+            <xsd:element name="subtitle_header" type="ffprobe:subtitleHeaderType" minOccurs="1" maxOccurs="1"/>
+            <xsd:element name="subtitle_rectangle" type="ffprobe:subtitleRectangleType" minOccurs="0" maxOccurs="unbounded"/>
+        </xsd:sequence>
+    </xsd:complexType>
+
+    <xsd:complexType name="subtitleHeaderType">
+      <xsd:attribute name="format"             type="xsd:int" use="required"/>
+      <xsd:attribute name="start_display_time" type="xsd:int" use="required"/>
+      <xsd:attribute name="end_display_time"   type="xsd:int" />
+      <xsd:attribute name="pts"                type="xsd:long" />
+      <xsd:attribute name="pts_time"           type="xsd:float"/>
+      <xsd:attribute name="pkt_pts"            type="xsd:long" />
+      <xsd:attribute name="pkt_pts_time"       type="xsd:float"/>
+    </xsd:complexType>
+
+    <xsd:complexType name="subtitleRectangleType">
+      <xsd:attribute name="type"     type="xsd:string" use="required"/>
+      <xsd:attribute name="x"        type="xsd:int"/>
+      <xsd:attribute name="y"        type="xsd:int" />
+      <xsd:attribute name="w"        type="xsd:int" />
+      <xsd:attribute name="h"        type="xsd:int" />
+      <xsd:attribute name="text_len" type="xsd:int" />
+      <xsd:attribute name="ass_len"  type="xsd:int" />
+      <xsd:attribute name="forced"   type="xsd:int" />
+    </xsd:complexType>
+
     <xsd:complexType name="streamsType">
         <xsd:sequence>
             <xsd:element name="stream" type="ffprobe:streamType" minOccurs="0" maxOccurs="unbounded"/>
diff --git a/ffprobe.c b/ffprobe.c
index 531cea2..d7639c6 100644
--- a/ffprobe.c
+++ b/ffprobe.c
@@ -263,6 +263,7 @@ static inline void writer_print_chapter_header(WriterContext *wctx,
     wctx->nb_section_packet_frame = 0;
     wctx->is_packets_and_frames = !strcmp(chapter, "packets_and_frames");
     wctx->multiple_sections = !strcmp(chapter, "packets") || !strcmp(chapter, "frames" ) ||
+                              !strcmp(chapter, "subtitle") ||
                               wctx->is_packets_and_frames ||
                               !strcmp(chapter, "streams") || !strcmp(chapter, "library_versions");
     wctx->is_fmt_chapter = !strcmp(chapter, "format");
@@ -1653,12 +1654,65 @@ static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream)
     fflush(stdout);
 }
 
+static void show_subtitle(WriterContext *w, AVSubtitle *sub, AVPacket *pkt,
+                          AVStream *stream)
+{
+    AVRational tb = AV_TIME_BASE_Q;
+    unsigned i;
+    static const char *const type_map[] = {
+        [SUBTITLE_NONE]   = "none",
+        [SUBTITLE_BITMAP] = "bitmap",
+        [SUBTITLE_TEXT]   = "text",
+        [SUBTITLE_ASS]    = "ass",
+    };
+
+    writer_print_chapter_header(w, "subtitle");
+
+    print_section_header("subtitle_header");
+    print_int ("format",             sub->format); /* TODO decode */
+    print_int ("start_display_time", sub->start_display_time);
+    print_int ("end_display_time",   sub->end_display_time);
+    print_ts  ("pts",                sub->pts);
+    print_time("pts_time",           sub->pts, &tb);
+    print_ts  ("pkt_pts",            pkt->pts);
+    print_time("pkt_pts_time",       pkt->pts, &stream->time_base);
+    print_section_footer("subtitle");
+
+    for (i = 0; i < sub->num_rects; i++) {
+        AVSubtitleRect *r = sub->rects[i];
+        print_section_header("subtitle_rectangle");
+        print_str("type", (unsigned)r->type < FF_ARRAY_ELEMS(type_map) ?
+                          type_map[r->type] : "unknown");
+        if (r->type == SUBTITLE_BITMAP) {
+            print_int("x", r->x);
+            print_int("y", r->y);
+            print_int("w", r->w);
+            print_int("h", r->h);
+        }
+        if (r->text)
+            print_int("text_len", strlen(r->text));
+        else
+            print_str_opt("text_len", "N/A");
+        if (r->ass)
+            print_int("ass_len", strlen(r->ass));
+        else
+            print_str_opt("ass_len", "N/A");
+        print_int("forced", r->forced);
+        print_section_footer("subtitle_rectangle");
+
+    }
+
+    writer_print_chapter_footer(w, "subtitle");
+    fflush(stdout);
+}
+
 static av_always_inline int process_decoded_frame(WriterContext *w,
                                                   AVFormatContext *fmt_ctx,
                                                   AVFrame *frame, AVPacket *pkt)
 {
     AVCodecContext *dec_ctx = fmt_ctx->streams[pkt->stream_index]->codec;
-    int ret = 0, got_frame = 0;
+    int ret = 0, got_frame = 0, got_sub = 0;
+    AVSubtitle subtitle;
 
     avcodec_get_frame_defaults(frame);
     if (dec_ctx->codec) {
@@ -1672,6 +1726,10 @@ static av_always_inline int process_decoded_frame(WriterContext *w,
         case AVMEDIA_TYPE_AUDIO:
             ret = avcodec_decode_audio4(dec_ctx, frame, &got_frame, pkt);
             break;
+
+        case AVMEDIA_TYPE_SUBTITLE:
+            ret = avcodec_decode_subtitle2(dec_ctx, &subtitle, &got_sub, pkt);
+            break;
         }
     }
 
@@ -1679,10 +1737,12 @@ static av_always_inline int process_decoded_frame(WriterContext *w,
         return ret;
     pkt->data += ret;
     pkt->size -= ret;
-    if (got_frame) {
-        nb_streams_frames[pkt->stream_index]++;
-        if (do_show_frames)
-            show_frame(w, frame, fmt_ctx->streams[pkt->stream_index]);
+    nb_streams_frames[pkt->stream_index] += got_frame || got_sub;
+    if (do_show_frames) {
+        if (got_frame)
+                show_frame(w, frame, fmt_ctx->streams[pkt->stream_index]);
+        if (got_sub)
+            show_subtitle(w, &subtitle, pkt, fmt_ctx->streams[pkt->stream_index]);
     }
     return got_frame;
 }
-- 
1.7.10.4



More information about the ffmpeg-devel mailing list