Browse code

ffprobe: show chapter and chapter metadata information

Address trac ticket #2636.

Stefano Sabatini authored on 2013/06/06 16:54:58
Showing 4 changed files
... ...
@@ -64,6 +64,7 @@ version <next>:
64 64
 - Go2Webinar decoder
65 65
 - mcdeint filter ported from libmpcodecs
66 66
 - sab filter ported from libmpcodecs
67
+- ffprobe -show_chapters option
67 68
 
68 69
 
69 70
 version 1.2:
... ...
@@ -209,6 +209,11 @@ multimedia stream.
209 209
 Each media stream information is printed within a dedicated section
210 210
 with name "STREAM".
211 211
 
212
+@item -show_chapters
213
+Show information about chapters stored in the format.
214
+
215
+Each chapter is printed within a dedicated section with name "CHAPTER".
216
+
212 217
 @item -count_frames
213 218
 Count the number of frames per stream and report it in the
214 219
 corresponding stream section.
... ...
@@ -11,6 +11,7 @@
11 11
             <xsd:element name="packets"  type="ffprobe:packetsType" minOccurs="0" maxOccurs="1" />
12 12
             <xsd:element name="frames"   type="ffprobe:framesType"  minOccurs="0" maxOccurs="1" />
13 13
             <xsd:element name="streams"  type="ffprobe:streamsType" minOccurs="0" maxOccurs="1" />
14
+            <xsd:element name="chapters" type="ffprobe:chaptersType" minOccurs="0" maxOccurs="1" />
14 15
             <xsd:element name="format"   type="ffprobe:formatType"  minOccurs="0" maxOccurs="1" />
15 16
             <xsd:element name="error"    type="ffprobe:errorType"   minOccurs="0" maxOccurs="1" />
16 17
             <xsd:element name="program_version"  type="ffprobe:programVersionType"  minOccurs="0" maxOccurs="1" />
... ...
@@ -181,6 +182,25 @@
181 181
       <xsd:attribute name="configuration"    type="xsd:string" use="required"/>
182 182
     </xsd:complexType>
183 183
 
184
+    <xsd:complexType name="chaptersType">
185
+      <xsd:sequence>
186
+        <xsd:element name="chapter" type="ffprobe:chapterType" minOccurs="0" maxOccurs="unbounded"/>
187
+      </xsd:sequence>
188
+    </xsd:complexType>
189
+
190
+    <xsd:complexType name="chapterType">
191
+      <xsd:sequence>
192
+        <xsd:element name="tag" type="ffprobe:tagType" minOccurs="0" maxOccurs="unbounded"/>
193
+      </xsd:sequence>
194
+
195
+      <xsd:attribute name="id"         type="xsd:int" use="required"/>
196
+      <xsd:attribute name="time_base"  type="xsd:string" use="required"/>
197
+      <xsd:attribute name="start"      type="xsd:int" use="required"/>
198
+      <xsd:attribute name="start_time" type="xsd:float"/>
199
+      <xsd:attribute name="end"        type="xsd:int" use="required"/>
200
+      <xsd:attribute name="end_time"   type="xsd:float" use="required"/>
201
+    </xsd:complexType>
202
+
184 203
     <xsd:complexType name="libraryVersionType">
185 204
       <xsd:attribute name="name"        type="xsd:string" use="required"/>
186 205
       <xsd:attribute name="major"       type="xsd:int"    use="required"/>
... ...
@@ -52,6 +52,7 @@ static int do_count_frames = 0;
52 52
 static int do_count_packets = 0;
53 53
 static int do_read_frames  = 0;
54 54
 static int do_read_packets = 0;
55
+static int do_show_chapters = 0;
55 56
 static int do_show_error   = 0;
56 57
 static int do_show_format  = 0;
57 58
 static int do_show_frames  = 0;
... ...
@@ -93,6 +94,9 @@ struct section {
93 93
 
94 94
 typedef enum {
95 95
     SECTION_ID_NONE = -1,
96
+    SECTION_ID_CHAPTER,
97
+    SECTION_ID_CHAPTER_TAGS,
98
+    SECTION_ID_CHAPTERS,
96 99
     SECTION_ID_ERROR,
97 100
     SECTION_ID_FORMAT,
98 101
     SECTION_ID_FORMAT_TAGS,
... ...
@@ -113,6 +117,9 @@ typedef enum {
113 113
 } SectionID;
114 114
 
115 115
 static struct section sections[] = {
116
+    [SECTION_ID_CHAPTERS] =           { SECTION_ID_CHAPTERS, "chapters", SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } },
117
+    [SECTION_ID_CHAPTER] =            { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } },
118
+    [SECTION_ID_CHAPTER_TAGS] =       { SECTION_ID_CHAPTER_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" },
116 119
     [SECTION_ID_ERROR] =              { SECTION_ID_ERROR, "error", 0, { -1 } },
117 120
     [SECTION_ID_FORMAT] =             { SECTION_ID_FORMAT, "format", 0, { SECTION_ID_FORMAT_TAGS, -1 } },
118 121
     [SECTION_ID_FORMAT_TAGS] =        { SECTION_ID_FORMAT_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "format_tags" },
... ...
@@ -126,7 +133,7 @@ static struct section sections[] = {
126 126
     [SECTION_ID_PACKET] =             { SECTION_ID_PACKET, "packet", 0, { -1 } },
127 127
     [SECTION_ID_PROGRAM_VERSION] =    { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } },
128 128
     [SECTION_ID_ROOT] =               { SECTION_ID_ROOT, "root", SECTION_FLAG_IS_WRAPPER,
129
-                                        { SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_STREAMS, SECTION_ID_PACKETS,
129
+                                        { SECTION_ID_CHAPTERS, SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_STREAMS, SECTION_ID_PACKETS,
130 130
                                           SECTION_ID_ERROR, SECTION_ID_PROGRAM_VERSION, SECTION_ID_LIBRARY_VERSIONS, -1} },
131 131
     [SECTION_ID_STREAMS] =            { SECTION_ID_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM, -1 } },
132 132
     [SECTION_ID_STREAM] =             { SECTION_ID_STREAM, "stream", 0, { SECTION_ID_STREAM_DISPOSITION, SECTION_ID_STREAM_TAGS, -1 } },
... ...
@@ -1751,6 +1758,27 @@ static void show_streams(WriterContext *w, AVFormatContext *fmt_ctx)
1751 1751
     writer_print_section_footer(w);
1752 1752
 }
1753 1753
 
1754
+static void show_chapters(WriterContext *w, AVFormatContext *fmt_ctx)
1755
+{
1756
+    int i;
1757
+
1758
+    writer_print_section_header(w, SECTION_ID_CHAPTERS);
1759
+    for (i = 0; i < fmt_ctx->nb_chapters; i++) {
1760
+        AVChapter *chapter = fmt_ctx->chapters[i];
1761
+
1762
+        writer_print_section_header(w, SECTION_ID_CHAPTER);
1763
+        print_int("id", chapter->id);
1764
+        print_q  ("time_base", chapter->time_base, '/');
1765
+        print_int("start", chapter->start);
1766
+        print_time("start_time", chapter->start, &chapter->time_base);
1767
+        print_int("end", chapter->end);
1768
+        print_time("end_time", chapter->end, &chapter->time_base);
1769
+        show_tags(w, chapter->metadata, SECTION_ID_CHAPTER_TAGS);
1770
+        writer_print_section_footer(w);
1771
+    }
1772
+    writer_print_section_footer(w);
1773
+}
1774
+
1754 1775
 static void show_format(WriterContext *w, AVFormatContext *fmt_ctx)
1755 1776
 {
1756 1777
     char val_str[128];
... ...
@@ -1911,6 +1939,8 @@ static int probe_file(WriterContext *wctx, const char *filename)
1911 1911
         }
1912 1912
         if (do_show_streams)
1913 1913
             show_streams(wctx, fmt_ctx);
1914
+        if (do_show_chapters)
1915
+            show_chapters(wctx, fmt_ctx);
1914 1916
         if (do_show_format)
1915 1917
             show_format(wctx, fmt_ctx);
1916 1918
 
... ...
@@ -2165,6 +2195,7 @@ static int opt_show_versions(const char *opt, const char *arg)
2165 2165
         return 0;                                                       \
2166 2166
     }
2167 2167
 
2168
+DEFINE_OPT_SHOW_SECTION(chapters,         CHAPTERS);
2168 2169
 DEFINE_OPT_SHOW_SECTION(error,            ERROR);
2169 2170
 DEFINE_OPT_SHOW_SECTION(format,           FORMAT);
2170 2171
 DEFINE_OPT_SHOW_SECTION(frames,           FRAMES);
... ...
@@ -2199,6 +2230,7 @@ static const OptionDef real_options[] = {
2199 2199
       "show a set of specified entries", "entry_list" },
2200 2200
     { "show_packets", 0, {(void*)&opt_show_packets}, "show packets info" },
2201 2201
     { "show_streams", 0, {(void*)&opt_show_streams}, "show streams info" },
2202
+    { "show_chapters", 0, {(void*)&opt_show_chapters}, "show chapters info" },
2202 2203
     { "count_frames", OPT_BOOL, {(void*)&do_count_frames}, "count the number of frames per stream" },
2203 2204
     { "count_packets", OPT_BOOL, {(void*)&do_count_packets}, "count the number of packets per stream" },
2204 2205
     { "show_program_version",  0, {(void*)&opt_show_program_version},  "show ffprobe version" },
... ...
@@ -2253,6 +2285,7 @@ int main(int argc, char **argv)
2253 2253
     parse_options(NULL, argc, argv, options, opt_input_file);
2254 2254
 
2255 2255
     /* mark things to show, based on -show_entries */
2256
+    SET_DO_SHOW(CHAPTERS, chapters);
2256 2257
     SET_DO_SHOW(ERROR, error);
2257 2258
     SET_DO_SHOW(FORMAT, format);
2258 2259
     SET_DO_SHOW(FRAMES, frames);
... ...
@@ -2298,7 +2331,7 @@ int main(int argc, char **argv)
2298 2298
             ffprobe_show_library_versions(wctx);
2299 2299
 
2300 2300
         if (!input_filename &&
2301
-            ((do_show_format || do_show_streams || do_show_packets || do_show_error) ||
2301
+            ((do_show_format || do_show_streams || do_show_chapters || do_show_packets || do_show_error) ||
2302 2302
              (!do_show_program_version && !do_show_library_versions))) {
2303 2303
             show_usage();
2304 2304
             av_log(NULL, AV_LOG_ERROR, "You have to specify one input file.\n");