Browse code

ffprobe: add -show_programs option

The option is used to sort the streams by program.

Signed-off-by: Florent Tribouilloy <florent.tribouilloy@smartjog.com>
Signed-off-by: Stefano Sabatini <stefasab@gmail.com>

Florent Tribouilloy authored on 2013/07/25 19:55:40
Showing 11 changed files
... ...
@@ -5,6 +5,7 @@ version <next>
5 5
 
6 6
 - aecho filter
7 7
 - perspective filter ported from libmpcodecs
8
+- ffprobe -show_programs option
8 9
 
9 10
 
10 11
 version 2.0:
... ...
@@ -44,7 +44,8 @@ name (which may be shared by other sections), and an unique
44 44
 name. See the output of @option{sections}.
45 45
 
46 46
 Metadata tags stored in the container or in the streams are recognized
47
-and printed in the corresponding "FORMAT" or "STREAM" section.
47
+and printed in the corresponding "FORMAT", "STREAM" or "PROGRAM_STREAM"
48
+section.
48 49
 
49 50
 @c man end
50 51
 
... ...
@@ -209,6 +210,13 @@ multimedia stream.
209 209
 Each media stream information is printed within a dedicated section
210 210
 with name "STREAM".
211 211
 
212
+@item -show_programs
213
+Show information about programs and their streams contained in the input
214
+multimedia stream.
215
+
216
+Each media stream information is printed within a dedicated section
217
+with name "PROGRAM_STREAM".
218
+
212 219
 @item -show_chapters
213 220
 Show information about chapters stored in the format.
214 221
 
... ...
@@ -279,8 +287,8 @@ keyN=valN
279 279
 [/SECTION]
280 280
 @end example
281 281
 
282
-Metadata tags are printed as a line in the corresponding FORMAT or
283
-STREAM section, and are prefixed by the string "TAG:".
282
+Metadata tags are printed as a line in the corresponding FORMAT, STREAM or
283
+PROGRAM_STREAM section, and are prefixed by the string "TAG:".
284 284
 
285 285
 A description of the accepted options follows.
286 286
 
... ...
@@ -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="programs" type="ffprobe:programsType" minOccurs="0" maxOccurs="1" />
14 15
             <xsd:element name="chapters" type="ffprobe:chaptersType" minOccurs="0" maxOccurs="1" />
15 16
             <xsd:element name="format"   type="ffprobe:formatType"  minOccurs="0" maxOccurs="1" />
16 17
             <xsd:element name="error"    type="ffprobe:errorType"   minOccurs="0" maxOccurs="1" />
... ...
@@ -87,6 +88,12 @@
87 87
         </xsd:sequence>
88 88
     </xsd:complexType>
89 89
 
90
+    <xsd:complexType name="programsType">
91
+        <xsd:sequence>
92
+            <xsd:element name="program" type="ffprobe:programType" minOccurs="0" maxOccurs="unbounded"/>
93
+        </xsd:sequence>
94
+    </xsd:complexType>
95
+
90 96
     <xsd:complexType name="streamDispositionType">
91 97
       <xsd:attribute name="default"          type="xsd:int" use="required" />
92 98
       <xsd:attribute name="dub"              type="xsd:int" use="required" />
... ...
@@ -147,6 +154,23 @@
147 147
       <xsd:attribute name="nb_read_packets"  type="xsd:int"/>
148 148
     </xsd:complexType>
149 149
 
150
+    <xsd:complexType name="programType">
151
+      <xsd:sequence>
152
+        <xsd:element name="tag" type="ffprobe:tagType" minOccurs="0" maxOccurs="unbounded"/>
153
+        <xsd:element name="streams" type="ffprobe:streamsType" minOccurs="0" maxOccurs="1"/>
154
+      </xsd:sequence>
155
+
156
+      <xsd:attribute name="program_id"           type="xsd:int"    use="required"/>
157
+      <xsd:attribute name="program_num"          type="xsd:int"    use="required"/>
158
+      <xsd:attribute name="nb_streams"           type="xsd:int"    use="required"/>
159
+      <xsd:attribute name="start_time"           type="xsd:float"/>
160
+      <xsd:attribute name="start_pts"            type="xsd:long"/>
161
+      <xsd:attribute name="end_time"             type="xsd:float"/>
162
+      <xsd:attribute name="end_pts"              type="xsd:long"/>
163
+      <xsd:attribute name="pmt_pid"              type="xsd:int"    use="required"/>
164
+      <xsd:attribute name="pcr_pid"              type="xsd:int"    use="required"/>
165
+    </xsd:complexType>
166
+
150 167
     <xsd:complexType name="formatType">
151 168
       <xsd:sequence>
152 169
         <xsd:element name="tag" type="ffprobe:tagType" minOccurs="0" maxOccurs="unbounded"/>
... ...
@@ -57,6 +57,7 @@ static int do_show_error   = 0;
57 57
 static int do_show_format  = 0;
58 58
 static int do_show_frames  = 0;
59 59
 static int do_show_packets = 0;
60
+static int do_show_programs = 0;
60 61
 static int do_show_streams = 0;
61 62
 static int do_show_stream_disposition = 0;
62 63
 static int do_show_data    = 0;
... ...
@@ -108,7 +109,14 @@ typedef enum {
108 108
     SECTION_ID_PACKET,
109 109
     SECTION_ID_PACKETS,
110 110
     SECTION_ID_PACKETS_AND_FRAMES,
111
+    SECTION_ID_PROGRAM_STREAM_DISPOSITION,
112
+    SECTION_ID_PROGRAM_STREAM_TAGS,
113
+    SECTION_ID_PROGRAM,
114
+    SECTION_ID_PROGRAM_STREAMS,
115
+    SECTION_ID_PROGRAM_STREAM,
116
+    SECTION_ID_PROGRAM_TAGS,
111 117
     SECTION_ID_PROGRAM_VERSION,
118
+    SECTION_ID_PROGRAMS,
112 119
     SECTION_ID_ROOT,
113 120
     SECTION_ID_STREAM,
114 121
     SECTION_ID_STREAM_DISPOSITION,
... ...
@@ -131,10 +139,17 @@ static struct section sections[] = {
131 131
     [SECTION_ID_PACKETS] =            { SECTION_ID_PACKETS, "packets", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
132 132
     [SECTION_ID_PACKETS_AND_FRAMES] = { SECTION_ID_PACKETS_AND_FRAMES, "packets_and_frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
133 133
     [SECTION_ID_PACKET] =             { SECTION_ID_PACKET, "packet", 0, { -1 } },
134
+    [SECTION_ID_PROGRAM_STREAM_DISPOSITION] = { SECTION_ID_PROGRAM_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "program_stream_disposition" },
135
+    [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" },
136
+    [SECTION_ID_PROGRAM] =                    { SECTION_ID_PROGRAM, "program", 0, { SECTION_ID_PROGRAM_TAGS, SECTION_ID_PROGRAM_STREAMS, -1 } },
137
+    [SECTION_ID_PROGRAM_STREAMS] =            { SECTION_ID_PROGRAM_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM_STREAM, -1 }, .unique_name = "program_streams" },
138
+    [SECTION_ID_PROGRAM_STREAM] =             { SECTION_ID_PROGRAM_STREAM, "stream", 0, { SECTION_ID_PROGRAM_STREAM_DISPOSITION, SECTION_ID_PROGRAM_STREAM_TAGS, -1 }, .unique_name = "program_stream" },
139
+    [SECTION_ID_PROGRAM_TAGS] =               { SECTION_ID_PROGRAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_tags" },
134 140
     [SECTION_ID_PROGRAM_VERSION] =    { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } },
141
+    [SECTION_ID_PROGRAMS] =                   { SECTION_ID_PROGRAMS, "programs", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM, -1 } },
135 142
     [SECTION_ID_ROOT] =               { SECTION_ID_ROOT, "root", SECTION_FLAG_IS_WRAPPER,
136
-                                        { SECTION_ID_CHAPTERS, SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_STREAMS, SECTION_ID_PACKETS,
137
-                                          SECTION_ID_ERROR, SECTION_ID_PROGRAM_VERSION, SECTION_ID_LIBRARY_VERSIONS, -1} },
143
+                                        { SECTION_ID_CHAPTERS, SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_PROGRAMS, SECTION_ID_STREAMS,
144
+                                          SECTION_ID_PACKETS, SECTION_ID_ERROR, SECTION_ID_PROGRAM_VERSION, SECTION_ID_LIBRARY_VERSIONS, -1} },
138 145
     [SECTION_ID_STREAMS] =            { SECTION_ID_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM, -1 } },
139 146
     [SECTION_ID_STREAM] =             { SECTION_ID_STREAM, "stream", 0, { SECTION_ID_STREAM_DISPOSITION, SECTION_ID_STREAM_TAGS, -1 } },
140 147
     [SECTION_ID_STREAM_DISPOSITION] = { SECTION_ID_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_disposition" },
... ...
@@ -1611,7 +1626,7 @@ static void read_packets(WriterContext *w, AVFormatContext *fmt_ctx)
1611 1611
     }
1612 1612
 }
1613 1613
 
1614
-static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx)
1614
+static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, int in_program)
1615 1615
 {
1616 1616
     AVStream *stream = fmt_ctx->streams[stream_idx];
1617 1617
     AVCodecContext *dec_ctx;
... ...
@@ -1623,7 +1638,7 @@ static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_i
1623 1623
 
1624 1624
     av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
1625 1625
 
1626
-    writer_print_section_header(w, SECTION_ID_STREAM);
1626
+    writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM : SECTION_ID_STREAM);
1627 1627
 
1628 1628
     print_int("index", stream->index);
1629 1629
 
... ...
@@ -1739,7 +1754,7 @@ static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_i
1739 1739
     } while (0)
1740 1740
 
1741 1741
     if (do_show_stream_disposition) {
1742
-    writer_print_section_header(w, SECTION_ID_STREAM_DISPOSITION);
1742
+    writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM_DISPOSITION : SECTION_ID_STREAM_DISPOSITION);
1743 1743
     PRINT_DISPOSITION(DEFAULT,          "default");
1744 1744
     PRINT_DISPOSITION(DUB,              "dub");
1745 1745
     PRINT_DISPOSITION(ORIGINAL,         "original");
... ...
@@ -1754,7 +1769,7 @@ static void show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_i
1754 1754
     writer_print_section_footer(w);
1755 1755
     }
1756 1756
 
1757
-    show_tags(w, stream->metadata, SECTION_ID_STREAM_TAGS);
1757
+    show_tags(w, stream->metadata, in_program ? SECTION_ID_PROGRAM_STREAM_TAGS : SECTION_ID_STREAM_TAGS);
1758 1758
 
1759 1759
     writer_print_section_footer(w);
1760 1760
     av_bprint_finalize(&pbuf, NULL);
... ...
@@ -1767,7 +1782,47 @@ static void show_streams(WriterContext *w, AVFormatContext *fmt_ctx)
1767 1767
     writer_print_section_header(w, SECTION_ID_STREAMS);
1768 1768
     for (i = 0; i < fmt_ctx->nb_streams; i++)
1769 1769
         if (selected_streams[i])
1770
-            show_stream(w, fmt_ctx, i);
1770
+            show_stream(w, fmt_ctx, i, 0);
1771
+    writer_print_section_footer(w);
1772
+}
1773
+
1774
+static void show_program(WriterContext *w, AVFormatContext *fmt_ctx, AVProgram *program)
1775
+{
1776
+    int i;
1777
+
1778
+    writer_print_section_header(w, SECTION_ID_PROGRAM);
1779
+    print_int("program_id", program->id);
1780
+    print_int("program_num", program->program_num);
1781
+    print_int("nb_streams", program->nb_stream_indexes);
1782
+    print_int("pmt_pid", program->pmt_pid);
1783
+    print_int("pcr_pid", program->pcr_pid);
1784
+    print_ts("start_pts", program->start_time);
1785
+    print_time("start_time", program->start_time, &AV_TIME_BASE_Q);
1786
+    print_ts("end_pts", program->end_time);
1787
+    print_time("end_time", program->end_time, &AV_TIME_BASE_Q);
1788
+    show_tags(w, program->metadata, SECTION_ID_PROGRAM_TAGS);
1789
+
1790
+    writer_print_section_header(w, SECTION_ID_PROGRAM_STREAMS);
1791
+    for (i = 0; i < program->nb_stream_indexes; i++) {
1792
+        if (selected_streams[program->stream_index[i]])
1793
+            show_stream(w, fmt_ctx, program->stream_index[i], 1);
1794
+    }
1795
+    writer_print_section_footer(w);
1796
+
1797
+    writer_print_section_footer(w);
1798
+}
1799
+
1800
+static void show_programs(WriterContext *w, AVFormatContext *fmt_ctx)
1801
+{
1802
+    int i;
1803
+
1804
+    writer_print_section_header(w, SECTION_ID_PROGRAMS);
1805
+    for (i = 0; i < fmt_ctx->nb_programs; i++) {
1806
+        AVProgram *program = fmt_ctx->programs[i];
1807
+        if (!program)
1808
+            continue;
1809
+        show_program(w, fmt_ctx, program);
1810
+    }
1771 1811
     writer_print_section_footer(w);
1772 1812
 }
1773 1813
 
... ...
@@ -1800,6 +1855,7 @@ static void show_format(WriterContext *w, AVFormatContext *fmt_ctx)
1800 1800
     writer_print_section_header(w, SECTION_ID_FORMAT);
1801 1801
     print_str("filename",         fmt_ctx->filename);
1802 1802
     print_int("nb_streams",       fmt_ctx->nb_streams);
1803
+    print_int("nb_programs",      fmt_ctx->nb_programs);
1803 1804
     print_str("format_name",      fmt_ctx->iformat->name);
1804 1805
     if (!do_bitexact) {
1805 1806
         if (fmt_ctx->iformat->long_name) print_str    ("format_long_name", fmt_ctx->iformat->long_name);
... ...
@@ -1953,6 +2009,8 @@ static int probe_file(WriterContext *wctx, const char *filename)
1953 1953
         if (do_show_frames || do_show_packets)
1954 1954
             writer_print_section_footer(wctx);
1955 1955
     }
1956
+    if (do_show_programs)
1957
+        show_programs(wctx, fmt_ctx);
1956 1958
     if (do_show_streams)
1957 1959
         show_streams(wctx, fmt_ctx);
1958 1960
     if (do_show_chapters)
... ...
@@ -2219,6 +2277,7 @@ DEFINE_OPT_SHOW_SECTION(library_versions, LIBRARY_VERSIONS);
2219 2219
 DEFINE_OPT_SHOW_SECTION(packets,          PACKETS);
2220 2220
 DEFINE_OPT_SHOW_SECTION(program_version,  PROGRAM_VERSION);
2221 2221
 DEFINE_OPT_SHOW_SECTION(streams,          STREAMS);
2222
+DEFINE_OPT_SHOW_SECTION(programs,         PROGRAMS);
2222 2223
 
2223 2224
 static const OptionDef real_options[] = {
2224 2225
 #include "cmdutils_common_opts.h"
... ...
@@ -2245,6 +2304,7 @@ static const OptionDef real_options[] = {
2245 2245
     { "show_entries", HAS_ARG, {.func_arg = opt_show_entries},
2246 2246
       "show a set of specified entries", "entry_list" },
2247 2247
     { "show_packets", 0, {(void*)&opt_show_packets}, "show packets info" },
2248
+    { "show_programs", 0, {(void*)&opt_show_programs}, "show programs info" },
2248 2249
     { "show_streams", 0, {(void*)&opt_show_streams}, "show streams info" },
2249 2250
     { "show_chapters", 0, {(void*)&opt_show_chapters}, "show chapters info" },
2250 2251
     { "count_frames", OPT_BOOL, {(void*)&do_count_frames}, "count the number of frames per stream" },
... ...
@@ -2308,8 +2368,10 @@ int main(int argc, char **argv)
2308 2308
     SET_DO_SHOW(LIBRARY_VERSIONS, library_versions);
2309 2309
     SET_DO_SHOW(PACKETS, packets);
2310 2310
     SET_DO_SHOW(PROGRAM_VERSION, program_version);
2311
+    SET_DO_SHOW(PROGRAMS, programs);
2311 2312
     SET_DO_SHOW(STREAMS, streams);
2312 2313
     SET_DO_SHOW(STREAM_DISPOSITION, stream_disposition);
2314
+    SET_DO_SHOW(PROGRAM_STREAM_DISPOSITION, stream_disposition);
2313 2315
 
2314 2316
     if (do_bitexact && (do_show_program_version || do_show_library_versions)) {
2315 2317
         av_log(NULL, AV_LOG_ERROR,
... ...
@@ -2347,7 +2409,7 @@ int main(int argc, char **argv)
2347 2347
             ffprobe_show_library_versions(wctx);
2348 2348
 
2349 2349
         if (!input_filename &&
2350
-            ((do_show_format || do_show_streams || do_show_chapters || do_show_packets || do_show_error) ||
2350
+            ((do_show_format || do_show_programs || do_show_streams || do_show_chapters || do_show_packets || do_show_error) ||
2351 2351
              (!do_show_program_version && !do_show_library_versions))) {
2352 2352
             show_usage();
2353 2353
             av_log(NULL, AV_LOG_ERROR, "You have to specify one input file.\n");
... ...
@@ -29,4 +29,4 @@ frame|media_type=video|key_frame=1|pkt_pts=6144|pkt_pts_time=0.120000|pkt_dts=61
29 29
 stream|index=0|codec_name=pcm_s16le|profile=unknown|codec_type=audio|codec_time_base=1/44100|codec_tag_string=PSD[16]|codec_tag=0x10445350|sample_fmt=s16|sample_rate=44100|channels=1|bits_per_sample=16|id=N/A|r_frame_rate=0/0|avg_frame_rate=0/0|time_base=1/44100|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=705600|nb_frames=N/A|nb_read_frames=6|nb_read_packets=6|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|tag:E=mc²
30 30
 stream|index=1|codec_name=rawvideo|profile=unknown|codec_type=video|codec_time_base=1/51200|codec_tag_string=RGB[24]|codec_tag=0x18424752|width=320|height=240|has_b_frames=0|sample_aspect_ratio=1:1|display_aspect_ratio=4:3|pix_fmt=rgb24|level=-99|timecode=N/A|id=N/A|r_frame_rate=25/1|avg_frame_rate=25/1|time_base=1/51200|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=N/A|nb_frames=N/A|nb_read_frames=4|nb_read_packets=4|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|tag:title=foobar|tag:duration_ts=field-and-tags-conflict-attempt
31 31
 stream|index=2|codec_name=rawvideo|profile=unknown|codec_type=video|codec_time_base=1/51200|codec_tag_string=RGB[24]|codec_tag=0x18424752|width=100|height=100|has_b_frames=0|sample_aspect_ratio=1:1|display_aspect_ratio=1:1|pix_fmt=rgb24|level=-99|timecode=N/A|id=N/A|r_frame_rate=25/1|avg_frame_rate=25/1|time_base=1/51200|start_pts=0|start_time=0.000000|duration_ts=N/A|duration=N/A|bit_rate=N/A|nb_frames=N/A|nb_read_frames=4|nb_read_packets=4|disposition:default=0|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0
32
-format|filename=tests/data/ffprobe-test.nut|nb_streams=3|format_name=nut|start_time=0.000000|duration=0.120000|size=1054812|bit_rate=70320800|tag:title=ffprobe test file|tag:comment='A comment with CSV, XML & JSON special chars': <tag value="x">|tag:comment2=I ♥ Üñîçød€
32
+format|filename=tests/data/ffprobe-test.nut|nb_streams=3|nb_programs=0|format_name=nut|start_time=0.000000|duration=0.120000|size=1054812|bit_rate=70320800|tag:title=ffprobe test file|tag:comment='A comment with CSV, XML & JSON special chars': <tag value="x">|tag:comment2=I ♥ Üñîçød€
... ...
@@ -29,4 +29,4 @@ frame,video,1,6144,0.120000,6144,0.120000,2048,0.040000,1024731,N/A,100,100,rgb2
29 29
 stream,0,pcm_s16le,unknown,audio,1/44100,PSD[16],0x10445350,s16,44100,1,16,N/A,0/0,0/0,1/44100,0,0.000000,N/A,N/A,705600,N/A,6,6,0,0,0,0,0,0,0,0,0,0,0,mc²
30 30
 stream,1,rawvideo,unknown,video,1/51200,RGB[24],0x18424752,320,240,0,1:1,4:3,rgb24,-99,N/A,N/A,25/1,25/1,1/51200,0,0.000000,N/A,N/A,N/A,N/A,4,4,0,0,0,0,0,0,0,0,0,0,0,foobar,field-and-tags-conflict-attempt
31 31
 stream,2,rawvideo,unknown,video,1/51200,RGB[24],0x18424752,100,100,0,1:1,1:1,rgb24,-99,N/A,N/A,25/1,25/1,1/51200,0,0.000000,N/A,N/A,N/A,N/A,4,4,0,0,0,0,0,0,0,0,0,0,0
32
-format,tests/data/ffprobe-test.nut,3,nut,0.000000,0.120000,1054812,70320800,ffprobe test file,"'A comment with CSV, XML & JSON special chars': <tag value=""x"">",I ♥ Üñîçød€
32
+format,tests/data/ffprobe-test.nut,3,0,nut,0.000000,0.120000,1054812,70320800,ffprobe test file,"'A comment with CSV, XML & JSON special chars': <tag value=""x"">",I ♥ Üñîçød€
... ...
@@ -602,6 +602,7 @@ DISPOSITION:attached_pic=0
602 602
 [FORMAT]
603 603
 filename=tests/data/ffprobe-test.nut
604 604
 nb_streams=3
605
+nb_programs=0
605 606
 format_name=nut
606 607
 start_time=0.000000
607 608
 duration=0.120000
... ...
@@ -539,6 +539,7 @@ streams.stream.2.disposition.clean_effects=0
539 539
 streams.stream.2.disposition.attached_pic=0
540 540
 format.filename="tests/data/ffprobe-test.nut"
541 541
 format.nb_streams=3
542
+format.nb_programs=0
542 543
 format.format_name="nut"
543 544
 format.start_time="0.000000"
544 545
 format.duration="0.120000"
... ...
@@ -614,6 +614,7 @@ attached_pic=0
614 614
 [format]
615 615
 filename=tests/data/ffprobe-test.nut
616 616
 nb_streams=3
617
+nb_programs=0
617 618
 format_name=nut
618 619
 start_time=0.000000
619 620
 duration=0.120000
... ...
@@ -584,6 +584,7 @@
584 584
     "format": {
585 585
         "filename": "tests/data/ffprobe-test.nut",
586 586
         "nb_streams": 3,
587
+        "nb_programs": 0,
587 588
         "format_name": "nut",
588 589
         "start_time": "0.000000",
589 590
         "duration": "0.120000",
... ...
@@ -46,7 +46,7 @@
46 46
         </stream>
47 47
     </streams>
48 48
 
49
-    <format filename="tests/data/ffprobe-test.nut" nb_streams="3" format_name="nut" start_time="0.000000" duration="0.120000" size="1054812" bit_rate="70320800">
49
+    <format filename="tests/data/ffprobe-test.nut" nb_streams="3" nb_programs="0" format_name="nut" start_time="0.000000" duration="0.120000" size="1054812" bit_rate="70320800">
50 50
         <tag key="title" value="ffprobe test file"/>
51 51
         <tag key="comment" value="&apos;A comment with CSV, XML &amp; JSON special chars&apos;: &lt;tag value=&quot;x&quot;&gt;"/>
52 52
         <tag key="comment2" value="I ♥ Üñîçød€"/>