[FFmpeg-devel] [RFC] ffprobe: add -show_pixel_descriptions option

Tobias Rapp t.rapp at noa-audio.com
Mon Sep 8 16:08:55 CEST 2014


As a follow-up to the "ffprobe: Add bits_per_component to stream output" 
discussion thread here comes my current state of adding pixel format 
detail output to ffprobe.

I'm still unsure if/how to output pixel format flags. Maybe as a simple 
white-space separated string "rgb alpha be"?

Any feedback or suggestions are welcome.

BTW: How can one test the ffprobe XML output against the XSD? I tried it 
with "xmllint --noout --schema doc/ffprobe.xsd ffprobe-output.xml" 
without success. What tools do other developers use?

Tobias
-------------- next part --------------
>From 513c99d6e6380a256fc168c62442bcb9c7278699 Mon Sep 17 00:00:00 2001
From: Tobias Rapp <t.rapp at noa-audio.com>
Date: Mon, 8 Sep 2014 15:48:12 +0200
Subject: [PATCH] ffprobe: add -show_pixel_descriptions option

Adds option -show_pixel_descriptions to ffprobe which lists all
available pixel formats with some details.
---
 doc/ffprobe.xsd | 15 +++++++++++
 ffprobe.c       | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 92 insertions(+), 2 deletions(-)

diff --git a/doc/ffprobe.xsd b/doc/ffprobe.xsd
index 32afa62..1fb9d9c 100644
--- a/doc/ffprobe.xsd
+++ b/doc/ffprobe.xsd
@@ -10,6 +10,7 @@
         <xsd:sequence>
             <xsd:element name="program_version"  type="ffprobe:programVersionType"  minOccurs="0" maxOccurs="1" />
             <xsd:element name="library_versions" type="ffprobe:libraryVersionsType" minOccurs="0" maxOccurs="1" />
+            <xsd:element name="pixel_descriptions" type="ffprobe:pixelDescriptionsType" minOccurs="0" maxOccurs="1" />
             <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="programs" type="ffprobe:programsType" minOccurs="0" maxOccurs="1" />
@@ -276,4 +277,18 @@
           <xsd:element name="library_version" type="ffprobe:libraryVersionType" minOccurs="0" maxOccurs="unbounded"/>
         </xsd:sequence>
     </xsd:complexType>
+
+    <xsd:complexType name="pixelDescriptionType">
+      <xsd:attribute name="name"                type="xsd:string" use="required"/>
+      <xsd:attribute name="nb_components"       type="xsd:int"    use="required"/>
+      <xsd:attribute name="bits_per_pixel"      type="xsd:int"/>
+      <xsd:attribute name="bits_per_component"  type="xsd:int"/>
+      <xsd:attribute name="chroma_sub_sampling" type="xsd:string"/>
+    </xsd:complexType>
+
+    <xsd:complexType name="pixelDescriptionsType">
+      <xsd:sequence>
+        <xsd:element name="pixel_description" type="ffprobe:pixelDescriptionType" minOccurs="0" maxOccurs="unbounded"/>
+      </xsd:sequence>
+    </xsd:complexType>
 </xsd:schema>
diff --git a/ffprobe.c b/ffprobe.c
index 2d48070..04a9946 100644
--- a/ffprobe.c
+++ b/ffprobe.c
@@ -66,6 +66,7 @@ static int do_show_stream_disposition = 0;
 static int do_show_data    = 0;
 static int do_show_program_version  = 0;
 static int do_show_library_versions = 0;
+static int do_show_pixel_descriptions = 0;
 
 static int do_show_chapter_tags = 0;
 static int do_show_format_tags = 0;
@@ -132,6 +133,8 @@ typedef enum {
     SECTION_ID_PACKET,
     SECTION_ID_PACKETS,
     SECTION_ID_PACKETS_AND_FRAMES,
+    SECTION_ID_PIXEL_DESCRIPTION,
+    SECTION_ID_PIXEL_DESCRIPTIONS,
     SECTION_ID_PROGRAM_STREAM_DISPOSITION,
     SECTION_ID_PROGRAM_STREAM_TAGS,
     SECTION_ID_PROGRAM,
@@ -165,6 +168,8 @@ static struct section sections[] = {
     [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_PIXEL_DESCRIPTIONS] = { SECTION_ID_PIXEL_DESCRIPTIONS, "pixel_descriptions", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PIXEL_DESCRIPTION, -1 } },
+    [SECTION_ID_PIXEL_DESCRIPTION] =  { SECTION_ID_PIXEL_DESCRIPTION, "pixel_description", 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_STREAMS, -1 } },
@@ -175,7 +180,8 @@ static struct section sections[] = {
     [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_PACKETS, SECTION_ID_ERROR, SECTION_ID_PROGRAM_VERSION, SECTION_ID_LIBRARY_VERSIONS,
+                                          SECTION_ID_PIXEL_DESCRIPTIONS, -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" },
@@ -2555,6 +2561,70 @@ static void ffprobe_show_library_versions(WriterContext *w)
     writer_print_section_footer(w);
 }
 
+static int get_bits_per_component(const AVPixFmtDescriptor *pixdesc)
+{
+    int c, bits, first_bits = 0;
+
+    for (c = 0; c < pixdesc->nb_components; c++) {
+        bits = pixdesc->comp[c].depth_minus1 + 1;
+        if (c == 0)
+            first_bits = bits;
+        else if (bits != first_bits)
+            return 0;
+    }
+
+    return first_bits;
+}
+
+static const char *get_chroma_sub_sample_string(const AVPixFmtDescriptor *pixdesc)
+{
+    if (!pixdesc)
+        return NULL;
+    if ((pixdesc->flags & AV_PIX_FMT_FLAG_RGB) || pixdesc->nb_components < 3)
+        return NULL;
+
+    if ((pixdesc->log2_chroma_w == 0) && (pixdesc->log2_chroma_h == 0))
+        return "4:4:4";
+    else if ((pixdesc->log2_chroma_w == 0) && (pixdesc->log2_chroma_h == 1))
+        return "4:4:0";
+    else if ((pixdesc->log2_chroma_w == 1) && (pixdesc->log2_chroma_h == 0))
+        return "4:2:2";
+    else if ((pixdesc->log2_chroma_w == 1) && (pixdesc->log2_chroma_h == 1))
+        return "4:2:0";
+    else if ((pixdesc->log2_chroma_w == 2) && (pixdesc->log2_chroma_h == 0))
+        return "4:1:1";
+    else if ((pixdesc->log2_chroma_w == 2) && (pixdesc->log2_chroma_h == 2))
+        return "4:1:0";
+    else
+        return "unknown";
+}
+
+static void ffprobe_show_pixel_descriptions(WriterContext *w)
+{
+    const AVPixFmtDescriptor *pixdesc = NULL;
+    enum AVPixelFormat pix_fmt;
+    const char *s;
+    int n, shift_h, shift_v;
+
+    writer_print_section_header(w, SECTION_ID_PIXEL_DESCRIPTIONS);
+    while (pixdesc = av_pix_fmt_desc_next(pixdesc)) {
+        writer_print_section_header(w, SECTION_ID_PIXEL_DESCRIPTION);
+        print_str("name", pixdesc->name);
+        print_int("nb_components", pixdesc->nb_components);
+        n = av_get_bits_per_pixel(pixdesc);
+        if (n) print_int    ("bits_per_pixel", n);
+        else   print_str_opt("bits_per_pixel", "N/A");
+        n = get_bits_per_component(pixdesc);
+        if (n) print_int    ("bits_per_component", n);
+        else   print_str_opt("bits_per_component", "N/A");
+        s = get_chroma_sub_sample_string(pixdesc);
+        if (s) print_str    ("chroma_sub_sampling", s);
+        else   print_str_opt("chroma_sub_sampling", "unknown");
+        writer_print_section_footer(w);
+    }
+    writer_print_section_footer(w);
+}
+
 static int opt_format(void *optctx, const char *opt, const char *arg)
 {
     iformat = av_find_input_format(arg);
@@ -2888,6 +2958,7 @@ DEFINE_OPT_SHOW_SECTION(format,           FORMAT);
 DEFINE_OPT_SHOW_SECTION(frames,           FRAMES);
 DEFINE_OPT_SHOW_SECTION(library_versions, LIBRARY_VERSIONS);
 DEFINE_OPT_SHOW_SECTION(packets,          PACKETS);
+DEFINE_OPT_SHOW_SECTION(pixel_descriptions, PIXEL_DESCRIPTIONS);
 DEFINE_OPT_SHOW_SECTION(program_version,  PROGRAM_VERSION);
 DEFINE_OPT_SHOW_SECTION(streams,          STREAMS);
 DEFINE_OPT_SHOW_SECTION(programs,         PROGRAMS);
@@ -2926,6 +2997,7 @@ static const OptionDef real_options[] = {
     { "show_program_version",  0, {(void*)&opt_show_program_version},  "show ffprobe version" },
     { "show_library_versions", 0, {(void*)&opt_show_library_versions}, "show library versions" },
     { "show_versions",         0, {(void*)&opt_show_versions}, "show program and library versions" },
+    { "show_pixel_descriptions", 0, {(void*)&opt_show_pixel_descriptions}, "show pixel format descriptions" },
     { "show_private_data", OPT_BOOL, {(void*)&show_private_data}, "show private data" },
     { "private",           OPT_BOOL, {(void*)&show_private_data}, "same as show_private_data" },
     { "bitexact", OPT_BOOL, {&do_bitexact}, "force bitexact output" },
@@ -2982,6 +3054,7 @@ int main(int argc, char **argv)
     SET_DO_SHOW(FRAMES, frames);
     SET_DO_SHOW(LIBRARY_VERSIONS, library_versions);
     SET_DO_SHOW(PACKETS, packets);
+    SET_DO_SHOW(PIXEL_DESCRIPTIONS, pixel_descriptions);
     SET_DO_SHOW(PROGRAM_VERSION, program_version);
     SET_DO_SHOW(PROGRAMS, programs);
     SET_DO_SHOW(STREAMS, streams);
@@ -3046,10 +3119,12 @@ int main(int argc, char **argv)
             ffprobe_show_program_version(wctx);
         if (do_show_library_versions)
             ffprobe_show_library_versions(wctx);
+        if (do_show_pixel_descriptions)
+            ffprobe_show_pixel_descriptions(wctx);
 
         if (!input_filename &&
             ((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))) {
+             (!do_show_program_version && !do_show_library_versions && !do_show_pixel_descriptions))) {
             show_usage();
             av_log(NULL, AV_LOG_ERROR, "You have to specify one input file.\n");
             av_log(NULL, AV_LOG_ERROR, "Use -h to get full help or, even better, run 'man %s'.\n", program_name);
-- 
1.9.1



More information about the ffmpeg-devel mailing list