[FFmpeg-devel] [PATCH] Add programs to ffprobe

Florent Tribouilloy florent.tribouilloy at smartjog.com
Fri Jul 19 15:24:50 CEST 2013


Option -show_programs for ffprobe will sort the output

Signed-off-by: Florent Tribouilloy <florent.tribouilloy at smartjog.com>
---
 doc/ffprobe.texi |   14 +++++--
 doc/ffprobe.xsd  |   26 +++++++++++++
 ffprobe.c        |  112 ++++++++++++++++++++++++++++++++++++++++--------------
 3 files changed, 121 insertions(+), 31 deletions(-)

diff --git a/doc/ffprobe.texi b/doc/ffprobe.texi
index 38517a8..02cffbb 100644
--- a/doc/ffprobe.texi
+++ b/doc/ffprobe.texi
@@ -44,7 +44,8 @@ name (which may be shared by other sections), and an unique
 name. See the output of @option{sections}.
 
 Metadata tags stored in the container or in the streams are recognized
-and printed in the corresponding "FORMAT" or "STREAM" section.
+and printed in the corresponding "FORMAT", "STREAM" or "PROGRAM_STREAM"
+section.
 
 @c man end
 
@@ -209,6 +210,13 @@ multimedia stream.
 Each media stream information is printed within a dedicated section
 with name "STREAM".
 
+ at item -show_programs
+Show information about programs and their streams contained in the input
+multimedia stream.
+
+Each media stream information is printed within a dedicated section
+with name "PROGRAM_STREAM".
+
 @item -show_chapters
 Show information about chapters stored in the format.
 
@@ -279,8 +287,8 @@ keyN=valN
 [/SECTION]
 @end example
 
-Metadata tags are printed as a line in the corresponding FORMAT or
-STREAM section, and are prefixed by the string "TAG:".
+Metadata tags are printed as a line in the corresponding FORMAT, STREAM or
+PROGRAM_STREAM section, and are prefixed by the string "TAG:".
 
 A description of the accepted options follows.
 
diff --git a/doc/ffprobe.xsd b/doc/ffprobe.xsd
index bd890b1..5716c7f 100644
--- a/doc/ffprobe.xsd
+++ b/doc/ffprobe.xsd
@@ -11,6 +11,7 @@
             <xsd:element name="packets"  type="ffprobe:packetsType" minOccurs="0" maxOccurs="1" />
             <xsd:element name="frames"   type="ffprobe:framesType"  minOccurs="0" maxOccurs="1" />
             <xsd:element name="streams"  type="ffprobe:streamsType" minOccurs="0" maxOccurs="1" />
+            <xsd:element name="programs" type="ffprobe:programsType" minOccurs="0" maxOccurs="1" />
             <xsd:element name="chapters" type="ffprobe:chaptersType" minOccurs="0" maxOccurs="1" />
             <xsd:element name="format"   type="ffprobe:formatType"  minOccurs="0" maxOccurs="1" />
             <xsd:element name="error"    type="ffprobe:errorType"   minOccurs="0" maxOccurs="1" />
@@ -87,6 +88,12 @@
         </xsd:sequence>
     </xsd:complexType>
 
+    <xsd:complexType name="programsType">
+        <xsd:sequence>
+            <xsd:element name="programs" type="ffprobe:programType" minOccurs="0" maxOccurs="unbounded"/>
+        </xsd:sequence>
+    </xsd:complexType>
+
     <xsd:complexType name="streamDispositionType">
       <xsd:attribute name="default"          type="xsd:int" use="required" />
       <xsd:attribute name="dub"              type="xsd:int" use="required" />
@@ -147,6 +154,25 @@
       <xsd:attribute name="nb_read_packets"  type="xsd:int"/>
     </xsd:complexType>
 
+    <xsd:complexType name="programType">
+      <xsd:sequence>
+        <xsd:element name="tag" type="ffprobe:tagType" minOccurs="0" maxOccurs="unbounded"/>
+      </xsd:sequence>
+
+      <xsd:attribute name="program_id"           type="xsd:int" use="required"/>
+      <xsd:attribute name="program_num"          type="xsd:int" use="required"/>
+      <xsd:attribute name="nb_stream"            type="xsd:int" use="required"/>
+      <xsd:attribute name="start_time"           type="xsd:int" use="required"/>
+      <xsd:attribute name="end_time"             type="xsd:int" use="required"/>
+      <xsd:attribute name="pmt_pid"              type="xsd:int" use="required"/>
+      <xsd:attribute name="pcr_pid"              type="xsd:int" use="required"/>
+      <xsd:attribute name="pts_wrap_reference"   type="xsd:int" use="required"/>
+      <xsd:attribute name="pts_wrap_behavior"    type="xsd:int" use="required"/>
+        <xsd:sequence>
+            <xsd:element name="program_stream" type="ffprobe:streamType" minOccurs="0" maxOccurs="unbounded"/>
+        </xsd:sequence>
+    </xsd:complexType>
+
     <xsd:complexType name="formatType">
       <xsd:sequence>
         <xsd:element name="tag" type="ffprobe:tagType" minOccurs="0" maxOccurs="unbounded"/>
diff --git a/ffprobe.c b/ffprobe.c
index d4adde0..d617592 100644
--- a/ffprobe.c
+++ b/ffprobe.c
@@ -57,6 +57,7 @@ static int do_show_error   = 0;
 static int do_show_format  = 0;
 static int do_show_frames  = 0;
 static int do_show_packets = 0;
+static int do_show_programs = 0;
 static int do_show_streams = 0;
 static int do_show_stream_disposition = 0;
 static int do_show_data    = 0;
@@ -108,7 +109,13 @@ typedef enum {
     SECTION_ID_PACKET,
     SECTION_ID_PACKETS,
     SECTION_ID_PACKETS_AND_FRAMES,
+    SECTION_ID_PROGRAM_STREAM_DISPOSITION,
+    SECTION_ID_PROGRAM_STREAM_TAGS,
+    SECTION_ID_PROGRAM,
+    SECTION_ID_PROGRAM_STREAM,
+    SECTION_ID_PROGRAM_TAGS,
     SECTION_ID_PROGRAM_VERSION,
+    SECTION_ID_PROGRAMS,
     SECTION_ID_ROOT,
     SECTION_ID_STREAM,
     SECTION_ID_STREAM_DISPOSITION,
@@ -117,28 +124,34 @@ typedef enum {
 } SectionID;
 
 static struct section sections[] = {
-    [SECTION_ID_CHAPTERS] =           { SECTION_ID_CHAPTERS, "chapters", SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } },
-    [SECTION_ID_CHAPTER] =            { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } },
-    [SECTION_ID_CHAPTER_TAGS] =       { SECTION_ID_CHAPTER_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" },
-    [SECTION_ID_ERROR] =              { SECTION_ID_ERROR, "error", 0, { -1 } },
-    [SECTION_ID_FORMAT] =             { SECTION_ID_FORMAT, "format", 0, { SECTION_ID_FORMAT_TAGS, -1 } },
-    [SECTION_ID_FORMAT_TAGS] =        { SECTION_ID_FORMAT_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "format_tags" },
-    [SECTION_ID_FRAMES] =             { SECTION_ID_FRAMES, "frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME, -1 } },
-    [SECTION_ID_FRAME] =              { SECTION_ID_FRAME, "frame", 0, { SECTION_ID_FRAME_TAGS, -1 } },
-    [SECTION_ID_FRAME_TAGS] =         { SECTION_ID_FRAME_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "frame_tags" },
-    [SECTION_ID_LIBRARY_VERSIONS] =   { SECTION_ID_LIBRARY_VERSIONS, "library_versions", SECTION_FLAG_IS_ARRAY, { SECTION_ID_LIBRARY_VERSION, -1 } },
-    [SECTION_ID_LIBRARY_VERSION] =    { SECTION_ID_LIBRARY_VERSION, "library_version", 0, { -1 } },
-    [SECTION_ID_PACKETS] =            { SECTION_ID_PACKETS, "packets", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
-    [SECTION_ID_PACKETS_AND_FRAMES] = { SECTION_ID_PACKETS_AND_FRAMES, "packets_and_frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
-    [SECTION_ID_PACKET] =             { SECTION_ID_PACKET, "packet", 0, { -1 } },
-    [SECTION_ID_PROGRAM_VERSION] =    { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } },
-    [SECTION_ID_ROOT] =               { SECTION_ID_ROOT, "root", SECTION_FLAG_IS_WRAPPER,
-                                        { SECTION_ID_CHAPTERS, SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_STREAMS, SECTION_ID_PACKETS,
-                                          SECTION_ID_ERROR, SECTION_ID_PROGRAM_VERSION, SECTION_ID_LIBRARY_VERSIONS, -1} },
-    [SECTION_ID_STREAMS] =            { SECTION_ID_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM, -1 } },
-    [SECTION_ID_STREAM] =             { SECTION_ID_STREAM, "stream", 0, { SECTION_ID_STREAM_DISPOSITION, SECTION_ID_STREAM_TAGS, -1 } },
-    [SECTION_ID_STREAM_DISPOSITION] = { SECTION_ID_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_disposition" },
-    [SECTION_ID_STREAM_TAGS] =        { SECTION_ID_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_tags" },
+    [SECTION_ID_CHAPTERS] =                   { SECTION_ID_CHAPTERS, "chapters", SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } },
+    [SECTION_ID_CHAPTER] =                    { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } },
+    [SECTION_ID_CHAPTER_TAGS] =               { SECTION_ID_CHAPTER_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" },
+    [SECTION_ID_ERROR] =                      { SECTION_ID_ERROR, "error", 0, { -1 } },
+    [SECTION_ID_FORMAT] =                     { SECTION_ID_FORMAT, "format", 0, { SECTION_ID_FORMAT_TAGS, -1 } },
+    [SECTION_ID_FORMAT_TAGS] =                { SECTION_ID_FORMAT_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "format_tags" },
+    [SECTION_ID_FRAMES] =                     { SECTION_ID_FRAMES, "frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME, -1 } },
+    [SECTION_ID_FRAME] =                      { SECTION_ID_FRAME, "frame", 0, { SECTION_ID_FRAME_TAGS, -1 } },
+    [SECTION_ID_FRAME_TAGS] =                 { SECTION_ID_FRAME_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "frame_tags" },
+    [SECTION_ID_LIBRARY_VERSIONS] =           { SECTION_ID_LIBRARY_VERSIONS, "library_versions", SECTION_FLAG_IS_ARRAY, { SECTION_ID_LIBRARY_VERSION, -1 } },
+    [SECTION_ID_LIBRARY_VERSION] =            { SECTION_ID_LIBRARY_VERSION, "library_version", 0, { -1 } },
+    [SECTION_ID_PACKETS] =                    { SECTION_ID_PACKETS, "packets", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
+    [SECTION_ID_PACKETS_AND_FRAMES] =         { SECTION_ID_PACKETS_AND_FRAMES, "packets_and_frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
+    [SECTION_ID_PACKET] =                     { SECTION_ID_PACKET, "packet", 0, { -1 } },
+    [SECTION_ID_PROGRAM_STREAM_DISPOSITION] = { SECTION_ID_PROGRAM_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "program_stream_disposition" },
+    [SECTION_ID_PROGRAM_STREAM_TAGS] =        { SECTION_ID_PROGRAM_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_stream_tags" },
+    [SECTION_ID_PROGRAM] =                    { SECTION_ID_PROGRAM, "program", 0, { SECTION_ID_PROGRAM_TAGS, SECTION_ID_PROGRAM_STREAM, -1 } },
+    [SECTION_ID_PROGRAM_STREAM] =             { SECTION_ID_PROGRAM_STREAM, "program_stream", 0, { SECTION_ID_PROGRAM_STREAM_DISPOSITION, SECTION_ID_PROGRAM_STREAM_TAGS, -1 } },
+    [SECTION_ID_PROGRAM_TAGS] =               { SECTION_ID_PROGRAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_tags" },
+    [SECTION_ID_PROGRAM_VERSION] =            { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } },
+    [SECTION_ID_PROGRAMS] =                   { SECTION_ID_PROGRAMS, "programs", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM, -1 } },
+    [SECTION_ID_ROOT] =                       { SECTION_ID_ROOT, "root", SECTION_FLAG_IS_WRAPPER,
+                                                { SECTION_ID_CHAPTERS, SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_PROGRAMS, SECTION_ID_STREAMS,
+                                                  SECTION_ID_PACKETS, SECTION_ID_ERROR, SECTION_ID_PROGRAM_VERSION, SECTION_ID_LIBRARY_VERSIONS, -1} },
+    [SECTION_ID_STREAMS] =                    { SECTION_ID_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM, -1 } },
+    [SECTION_ID_STREAM] =                     { SECTION_ID_STREAM, "stream", 0, { SECTION_ID_STREAM_DISPOSITION, SECTION_ID_STREAM_TAGS, -1 } },
+    [SECTION_ID_STREAM_DISPOSITION] =         { SECTION_ID_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_disposition" },
+    [SECTION_ID_STREAM_TAGS] =                { SECTION_ID_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_tags" },
 };
 
 static const OptionDef *options;
@@ -1598,7 +1611,7 @@ static void read_packets(WriterContext *w, AVFormatContext *fmt_ctx)
     }
 }
 
-static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx)
+static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, int in_program)
 {
     AVStream *stream = fmt_ctx->streams[stream_idx];
     AVCodecContext *dec_ctx;
@@ -1610,7 +1623,7 @@ static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_i
 
     av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
 
-    writer_print_section_header(w, SECTION_ID_STREAM);
+    writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM : SECTION_ID_STREAM);
 
     print_int("index", stream->index);
 
@@ -1726,7 +1739,7 @@ static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_i
     } while (0)
 
     if (do_show_stream_disposition) {
-    writer_print_section_header(w, SECTION_ID_STREAM_DISPOSITION);
+    writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM_DISPOSITION : SECTION_ID_STREAM_DISPOSITION);
     PRINT_DISPOSITION(DEFAULT,          "default");
     PRINT_DISPOSITION(DUB,              "dub");
     PRINT_DISPOSITION(ORIGINAL,         "original");
@@ -1741,7 +1754,7 @@ static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_i
     writer_print_section_footer(w);
     }
 
-    show_tags(w, stream->metadata, SECTION_ID_STREAM_TAGS);
+    show_tags(w, stream->metadata, in_program ? SECTION_ID_PROGRAM_STREAM_TAGS : SECTION_ID_STREAM_TAGS);
 
     writer_print_section_footer(w);
     av_bprint_finalize(&pbuf, NULL);
@@ -1754,7 +1767,43 @@ static void show_streams(WriterContext *w, AVFormatContext *fmt_ctx)
     writer_print_section_header(w, SECTION_ID_STREAMS);
     for (i = 0; i < fmt_ctx->nb_streams; i++)
         if (selected_streams[i])
-            show_stream(w, fmt_ctx, i);
+            show_stream(w, fmt_ctx, i, 0);
+    writer_print_section_footer(w);
+}
+
+static void show_program(WriterContext *w, AVFormatContext *fmt_ctx, AVProgram *program)
+{
+    int i;
+
+    writer_print_section_header(w, SECTION_ID_PROGRAM);
+    print_int("program_id", program->id);
+    print_int("program_num", program->program_num);
+    print_int("nb_stream", program->nb_stream_indexes);
+    print_int("start_time", program->start_time);
+    print_int("end_time", program->end_time);
+    print_int("pmt_pid", program->pmt_pid);
+    print_int("pcr_pid", program->pcr_pid);
+    print_int("pts_wrap_reference", program->pts_wrap_reference);
+    print_int("pts_wrap_behavior", program->pts_wrap_behavior);
+    show_tags(w, program->metadata, SECTION_ID_PROGRAM_TAGS);
+    for (i = 0; i < program->nb_stream_indexes; i++) {
+        if (selected_streams[program->stream_index[i]])
+            show_stream(w, fmt_ctx, program->stream_index[i], 1);
+    }
+    writer_print_section_footer(w);
+}
+
+static void show_programs(WriterContext *w, AVFormatContext *fmt_ctx)
+{
+    int i;
+
+    writer_print_section_header(w, SECTION_ID_PROGRAMS);
+    for (i = 0; i < fmt_ctx->nb_programs; i++) {
+        AVProgram *program = fmt_ctx->programs[i];
+        if (!program)
+            continue;
+        show_program(w, fmt_ctx, program);
+    }
     writer_print_section_footer(w);
 }
 
@@ -1787,6 +1836,7 @@ static void show_format(WriterContext *w, AVFormatContext *fmt_ctx)
     writer_print_section_header(w, SECTION_ID_FORMAT);
     print_str("filename",         fmt_ctx->filename);
     print_int("nb_streams",       fmt_ctx->nb_streams);
+    print_int("nb_programs",      fmt_ctx->nb_programs);
     print_str("format_name",      fmt_ctx->iformat->name);
     if (!do_bitexact) {
         if (fmt_ctx->iformat->long_name) print_str    ("format_long_name", fmt_ctx->iformat->long_name);
@@ -1940,6 +1990,8 @@ static int probe_file(WriterContext *wctx, const char *filename)
         if (do_show_frames || do_show_packets)
             writer_print_section_footer(wctx);
     }
+    if (do_show_programs)
+        show_programs(wctx, fmt_ctx);
     if (do_show_streams)
         show_streams(wctx, fmt_ctx);
     if (do_show_chapters)
@@ -2206,6 +2258,7 @@ DEFINE_OPT_SHOW_SECTION(library_versions, LIBRARY_VERSIONS);
 DEFINE_OPT_SHOW_SECTION(packets,          PACKETS);
 DEFINE_OPT_SHOW_SECTION(program_version,  PROGRAM_VERSION);
 DEFINE_OPT_SHOW_SECTION(streams,          STREAMS);
+DEFINE_OPT_SHOW_SECTION(programs,         PROGRAMS);
 
 static const OptionDef real_options[] = {
 #include "cmdutils_common_opts.h"
@@ -2232,6 +2285,7 @@ static const OptionDef real_options[] = {
     { "show_entries", HAS_ARG, {.func_arg = opt_show_entries},
       "show a set of specified entries", "entry_list" },
     { "show_packets", 0, {(void*)&opt_show_packets}, "show packets info" },
+    { "show_programs", 0, {(void*)&opt_show_programs}, "show programs info" },
     { "show_streams", 0, {(void*)&opt_show_streams}, "show streams info" },
     { "show_chapters", 0, {(void*)&opt_show_chapters}, "show chapters info" },
     { "count_frames", OPT_BOOL, {(void*)&do_count_frames}, "count the number of frames per stream" },
@@ -2295,8 +2349,10 @@ int main(int argc, char **argv)
     SET_DO_SHOW(LIBRARY_VERSIONS, library_versions);
     SET_DO_SHOW(PACKETS, packets);
     SET_DO_SHOW(PROGRAM_VERSION, program_version);
+    SET_DO_SHOW(PROGRAMS, programs);
     SET_DO_SHOW(STREAMS, streams);
     SET_DO_SHOW(STREAM_DISPOSITION, stream_disposition);
+    SET_DO_SHOW(PROGRAM_STREAM_DISPOSITION, stream_disposition);
 
     if (do_bitexact && (do_show_program_version || do_show_library_versions)) {
         av_log(NULL, AV_LOG_ERROR,
@@ -2334,7 +2390,7 @@ int main(int argc, char **argv)
             ffprobe_show_library_versions(wctx);
 
         if (!input_filename &&
-            ((do_show_format || do_show_streams || do_show_chapters || do_show_packets || do_show_error) ||
+            ((do_show_format || do_show_programs || do_show_streams || do_show_chapters || do_show_packets || do_show_error) ||
              (!do_show_program_version && !do_show_library_versions))) {
             show_usage();
             av_log(NULL, AV_LOG_ERROR, "You have to specify one input file.\n");
-- 
1.7.10.4



More information about the ffmpeg-devel mailing list