GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* |
||
2 |
* Copyright (c) 2007-2010 Stefano Sabatini |
||
3 |
* |
||
4 |
* This file is part of FFmpeg. |
||
5 |
* |
||
6 |
* FFmpeg is free software; you can redistribute it and/or |
||
7 |
* modify it under the terms of the GNU Lesser General Public |
||
8 |
* License as published by the Free Software Foundation; either |
||
9 |
* version 2.1 of the License, or (at your option) any later version. |
||
10 |
* |
||
11 |
* FFmpeg is distributed in the hope that it will be useful, |
||
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
14 |
* Lesser General Public License for more details. |
||
15 |
* |
||
16 |
* You should have received a copy of the GNU Lesser General Public |
||
17 |
* License along with FFmpeg; if not, write to the Free Software |
||
18 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||
19 |
*/ |
||
20 |
|||
21 |
/** |
||
22 |
* @file |
||
23 |
* simple media prober based on the FFmpeg libraries |
||
24 |
*/ |
||
25 |
|||
26 |
#include "config.h" |
||
27 |
#include "libavutil/ffversion.h" |
||
28 |
|||
29 |
#include <string.h> |
||
30 |
|||
31 |
#include "libavformat/avformat.h" |
||
32 |
#include "libavcodec/avcodec.h" |
||
33 |
#include "libavutil/avassert.h" |
||
34 |
#include "libavutil/avstring.h" |
||
35 |
#include "libavutil/bprint.h" |
||
36 |
#include "libavutil/display.h" |
||
37 |
#include "libavutil/hash.h" |
||
38 |
#include "libavutil/hdr_dynamic_metadata.h" |
||
39 |
#include "libavutil/mastering_display_metadata.h" |
||
40 |
#include "libavutil/dovi_meta.h" |
||
41 |
#include "libavutil/opt.h" |
||
42 |
#include "libavutil/pixdesc.h" |
||
43 |
#include "libavutil/spherical.h" |
||
44 |
#include "libavutil/stereo3d.h" |
||
45 |
#include "libavutil/dict.h" |
||
46 |
#include "libavutil/intreadwrite.h" |
||
47 |
#include "libavutil/libm.h" |
||
48 |
#include "libavutil/parseutils.h" |
||
49 |
#include "libavutil/timecode.h" |
||
50 |
#include "libavutil/timestamp.h" |
||
51 |
#include "libavdevice/avdevice.h" |
||
52 |
#include "libswscale/swscale.h" |
||
53 |
#include "libswresample/swresample.h" |
||
54 |
#include "libpostproc/postprocess.h" |
||
55 |
#include "cmdutils.h" |
||
56 |
|||
57 |
#include "libavutil/thread.h" |
||
58 |
|||
59 |
#if !HAVE_THREADS |
||
60 |
# ifdef pthread_mutex_lock |
||
61 |
# undef pthread_mutex_lock |
||
62 |
# endif |
||
63 |
# define pthread_mutex_lock(a) do{}while(0) |
||
64 |
# ifdef pthread_mutex_unlock |
||
65 |
# undef pthread_mutex_unlock |
||
66 |
# endif |
||
67 |
# define pthread_mutex_unlock(a) do{}while(0) |
||
68 |
#endif |
||
69 |
|||
70 |
typedef struct InputStream { |
||
71 |
AVStream *st; |
||
72 |
|||
73 |
AVCodecContext *dec_ctx; |
||
74 |
} InputStream; |
||
75 |
|||
76 |
typedef struct InputFile { |
||
77 |
AVFormatContext *fmt_ctx; |
||
78 |
|||
79 |
InputStream *streams; |
||
80 |
int nb_streams; |
||
81 |
} InputFile; |
||
82 |
|||
83 |
const char program_name[] = "ffprobe"; |
||
84 |
const int program_birth_year = 2007; |
||
85 |
|||
86 |
static int do_bitexact = 0; |
||
87 |
static int do_count_frames = 0; |
||
88 |
static int do_count_packets = 0; |
||
89 |
static int do_read_frames = 0; |
||
90 |
static int do_read_packets = 0; |
||
91 |
static int do_show_chapters = 0; |
||
92 |
static int do_show_error = 0; |
||
93 |
static int do_show_format = 0; |
||
94 |
static int do_show_frames = 0; |
||
95 |
static int do_show_packets = 0; |
||
96 |
static int do_show_programs = 0; |
||
97 |
static int do_show_streams = 0; |
||
98 |
static int do_show_stream_disposition = 0; |
||
99 |
static int do_show_data = 0; |
||
100 |
static int do_show_program_version = 0; |
||
101 |
static int do_show_library_versions = 0; |
||
102 |
static int do_show_pixel_formats = 0; |
||
103 |
static int do_show_pixel_format_flags = 0; |
||
104 |
static int do_show_pixel_format_components = 0; |
||
105 |
static int do_show_log = 0; |
||
106 |
|||
107 |
static int do_show_chapter_tags = 0; |
||
108 |
static int do_show_format_tags = 0; |
||
109 |
static int do_show_frame_tags = 0; |
||
110 |
static int do_show_program_tags = 0; |
||
111 |
static int do_show_stream_tags = 0; |
||
112 |
static int do_show_packet_tags = 0; |
||
113 |
|||
114 |
static int show_value_unit = 0; |
||
115 |
static int use_value_prefix = 0; |
||
116 |
static int use_byte_value_binary_prefix = 0; |
||
117 |
static int use_value_sexagesimal_format = 0; |
||
118 |
static int show_private_data = 1; |
||
119 |
|||
120 |
static char *print_format; |
||
121 |
static char *stream_specifier; |
||
122 |
static char *show_data_hash; |
||
123 |
|||
124 |
typedef struct ReadInterval { |
||
125 |
int id; ///< identifier |
||
126 |
int64_t start, end; ///< start, end in second/AV_TIME_BASE units |
||
127 |
int has_start, has_end; |
||
128 |
int start_is_offset, end_is_offset; |
||
129 |
int duration_frames; |
||
130 |
} ReadInterval; |
||
131 |
|||
132 |
static ReadInterval *read_intervals; |
||
133 |
static int read_intervals_nb = 0; |
||
134 |
|||
135 |
static int find_stream_info = 1; |
||
136 |
|||
137 |
/* section structure definition */ |
||
138 |
|||
139 |
#define SECTION_MAX_NB_CHILDREN 10 |
||
140 |
|||
141 |
struct section { |
||
142 |
int id; ///< unique id identifying a section |
||
143 |
const char *name; |
||
144 |
|||
145 |
#define SECTION_FLAG_IS_WRAPPER 1 ///< the section only contains other sections, but has no data at its own level |
||
146 |
#define SECTION_FLAG_IS_ARRAY 2 ///< the section contains an array of elements of the same type |
||
147 |
#define SECTION_FLAG_HAS_VARIABLE_FIELDS 4 ///< the section may contain a variable number of fields with variable keys. |
||
148 |
/// For these sections the element_name field is mandatory. |
||
149 |
int flags; |
||
150 |
int children_ids[SECTION_MAX_NB_CHILDREN+1]; ///< list of children section IDS, terminated by -1 |
||
151 |
const char *element_name; ///< name of the contained element, if provided |
||
152 |
const char *unique_name; ///< unique section name, in case the name is ambiguous |
||
153 |
AVDictionary *entries_to_show; |
||
154 |
int show_all_entries; |
||
155 |
}; |
||
156 |
|||
157 |
typedef enum { |
||
158 |
SECTION_ID_NONE = -1, |
||
159 |
SECTION_ID_CHAPTER, |
||
160 |
SECTION_ID_CHAPTER_TAGS, |
||
161 |
SECTION_ID_CHAPTERS, |
||
162 |
SECTION_ID_ERROR, |
||
163 |
SECTION_ID_FORMAT, |
||
164 |
SECTION_ID_FORMAT_TAGS, |
||
165 |
SECTION_ID_FRAME, |
||
166 |
SECTION_ID_FRAMES, |
||
167 |
SECTION_ID_FRAME_TAGS, |
||
168 |
SECTION_ID_FRAME_SIDE_DATA_LIST, |
||
169 |
SECTION_ID_FRAME_SIDE_DATA, |
||
170 |
SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, |
||
171 |
SECTION_ID_FRAME_SIDE_DATA_TIMECODE, |
||
172 |
SECTION_ID_FRAME_LOG, |
||
173 |
SECTION_ID_FRAME_LOGS, |
||
174 |
SECTION_ID_LIBRARY_VERSION, |
||
175 |
SECTION_ID_LIBRARY_VERSIONS, |
||
176 |
SECTION_ID_PACKET, |
||
177 |
SECTION_ID_PACKET_TAGS, |
||
178 |
SECTION_ID_PACKETS, |
||
179 |
SECTION_ID_PACKETS_AND_FRAMES, |
||
180 |
SECTION_ID_PACKET_SIDE_DATA_LIST, |
||
181 |
SECTION_ID_PACKET_SIDE_DATA, |
||
182 |
SECTION_ID_PIXEL_FORMAT, |
||
183 |
SECTION_ID_PIXEL_FORMAT_FLAGS, |
||
184 |
SECTION_ID_PIXEL_FORMAT_COMPONENT, |
||
185 |
SECTION_ID_PIXEL_FORMAT_COMPONENTS, |
||
186 |
SECTION_ID_PIXEL_FORMATS, |
||
187 |
SECTION_ID_PROGRAM_STREAM_DISPOSITION, |
||
188 |
SECTION_ID_PROGRAM_STREAM_TAGS, |
||
189 |
SECTION_ID_PROGRAM, |
||
190 |
SECTION_ID_PROGRAM_STREAMS, |
||
191 |
SECTION_ID_PROGRAM_STREAM, |
||
192 |
SECTION_ID_PROGRAM_TAGS, |
||
193 |
SECTION_ID_PROGRAM_VERSION, |
||
194 |
SECTION_ID_PROGRAMS, |
||
195 |
SECTION_ID_ROOT, |
||
196 |
SECTION_ID_STREAM, |
||
197 |
SECTION_ID_STREAM_DISPOSITION, |
||
198 |
SECTION_ID_STREAMS, |
||
199 |
SECTION_ID_STREAM_TAGS, |
||
200 |
SECTION_ID_STREAM_SIDE_DATA_LIST, |
||
201 |
SECTION_ID_STREAM_SIDE_DATA, |
||
202 |
SECTION_ID_SUBTITLE, |
||
203 |
} SectionID; |
||
204 |
|||
205 |
static struct section sections[] = { |
||
206 |
[SECTION_ID_CHAPTERS] = { SECTION_ID_CHAPTERS, "chapters", SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } }, |
||
207 |
[SECTION_ID_CHAPTER] = { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } }, |
||
208 |
[SECTION_ID_CHAPTER_TAGS] = { SECTION_ID_CHAPTER_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" }, |
||
209 |
[SECTION_ID_ERROR] = { SECTION_ID_ERROR, "error", 0, { -1 } }, |
||
210 |
[SECTION_ID_FORMAT] = { SECTION_ID_FORMAT, "format", 0, { SECTION_ID_FORMAT_TAGS, -1 } }, |
||
211 |
[SECTION_ID_FORMAT_TAGS] = { SECTION_ID_FORMAT_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "format_tags" }, |
||
212 |
[SECTION_ID_FRAMES] = { SECTION_ID_FRAMES, "frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME, SECTION_ID_SUBTITLE, -1 } }, |
||
213 |
[SECTION_ID_FRAME] = { SECTION_ID_FRAME, "frame", 0, { SECTION_ID_FRAME_TAGS, SECTION_ID_FRAME_SIDE_DATA_LIST, SECTION_ID_FRAME_LOGS, -1 } }, |
||
214 |
[SECTION_ID_FRAME_TAGS] = { SECTION_ID_FRAME_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "frame_tags" }, |
||
215 |
[SECTION_ID_FRAME_SIDE_DATA_LIST] ={ SECTION_ID_FRAME_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "frame_side_data_list" }, |
||
216 |
[SECTION_ID_FRAME_SIDE_DATA] = { SECTION_ID_FRAME_SIDE_DATA, "side_data", 0, { SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, -1 } }, |
||
217 |
[SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST] = { SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, "timecodes", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_TIMECODE, -1 } }, |
||
218 |
[SECTION_ID_FRAME_SIDE_DATA_TIMECODE] = { SECTION_ID_FRAME_SIDE_DATA_TIMECODE, "timecode", 0, { -1 } }, |
||
219 |
[SECTION_ID_FRAME_LOGS] = { SECTION_ID_FRAME_LOGS, "logs", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_LOG, -1 } }, |
||
220 |
[SECTION_ID_FRAME_LOG] = { SECTION_ID_FRAME_LOG, "log", 0, { -1 }, }, |
||
221 |
[SECTION_ID_LIBRARY_VERSIONS] = { SECTION_ID_LIBRARY_VERSIONS, "library_versions", SECTION_FLAG_IS_ARRAY, { SECTION_ID_LIBRARY_VERSION, -1 } }, |
||
222 |
[SECTION_ID_LIBRARY_VERSION] = { SECTION_ID_LIBRARY_VERSION, "library_version", 0, { -1 } }, |
||
223 |
[SECTION_ID_PACKETS] = { SECTION_ID_PACKETS, "packets", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} }, |
||
224 |
[SECTION_ID_PACKETS_AND_FRAMES] = { SECTION_ID_PACKETS_AND_FRAMES, "packets_and_frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} }, |
||
225 |
[SECTION_ID_PACKET] = { SECTION_ID_PACKET, "packet", 0, { SECTION_ID_PACKET_TAGS, SECTION_ID_PACKET_SIDE_DATA_LIST, -1 } }, |
||
226 |
[SECTION_ID_PACKET_TAGS] = { SECTION_ID_PACKET_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "packet_tags" }, |
||
227 |
[SECTION_ID_PACKET_SIDE_DATA_LIST] ={ SECTION_ID_PACKET_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "packet_side_data_list" }, |
||
228 |
[SECTION_ID_PACKET_SIDE_DATA] = { SECTION_ID_PACKET_SIDE_DATA, "side_data", 0, { -1 } }, |
||
229 |
[SECTION_ID_PIXEL_FORMATS] = { SECTION_ID_PIXEL_FORMATS, "pixel_formats", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PIXEL_FORMAT, -1 } }, |
||
230 |
[SECTION_ID_PIXEL_FORMAT] = { SECTION_ID_PIXEL_FORMAT, "pixel_format", 0, { SECTION_ID_PIXEL_FORMAT_FLAGS, SECTION_ID_PIXEL_FORMAT_COMPONENTS, -1 } }, |
||
231 |
[SECTION_ID_PIXEL_FORMAT_FLAGS] = { SECTION_ID_PIXEL_FORMAT_FLAGS, "flags", 0, { -1 }, .unique_name = "pixel_format_flags" }, |
||
232 |
[SECTION_ID_PIXEL_FORMAT_COMPONENTS] = { SECTION_ID_PIXEL_FORMAT_COMPONENTS, "components", SECTION_FLAG_IS_ARRAY, {SECTION_ID_PIXEL_FORMAT_COMPONENT, -1 }, .unique_name = "pixel_format_components" }, |
||
233 |
[SECTION_ID_PIXEL_FORMAT_COMPONENT] = { SECTION_ID_PIXEL_FORMAT_COMPONENT, "component", 0, { -1 } }, |
||
234 |
[SECTION_ID_PROGRAM_STREAM_DISPOSITION] = { SECTION_ID_PROGRAM_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "program_stream_disposition" }, |
||
235 |
[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" }, |
||
236 |
[SECTION_ID_PROGRAM] = { SECTION_ID_PROGRAM, "program", 0, { SECTION_ID_PROGRAM_TAGS, SECTION_ID_PROGRAM_STREAMS, -1 } }, |
||
237 |
[SECTION_ID_PROGRAM_STREAMS] = { SECTION_ID_PROGRAM_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM_STREAM, -1 }, .unique_name = "program_streams" }, |
||
238 |
[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" }, |
||
239 |
[SECTION_ID_PROGRAM_TAGS] = { SECTION_ID_PROGRAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "program_tags" }, |
||
240 |
[SECTION_ID_PROGRAM_VERSION] = { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } }, |
||
241 |
[SECTION_ID_PROGRAMS] = { SECTION_ID_PROGRAMS, "programs", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PROGRAM, -1 } }, |
||
242 |
[SECTION_ID_ROOT] = { SECTION_ID_ROOT, "root", SECTION_FLAG_IS_WRAPPER, |
||
243 |
{ SECTION_ID_CHAPTERS, SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_PROGRAMS, SECTION_ID_STREAMS, |
||
244 |
SECTION_ID_PACKETS, SECTION_ID_ERROR, SECTION_ID_PROGRAM_VERSION, SECTION_ID_LIBRARY_VERSIONS, |
||
245 |
SECTION_ID_PIXEL_FORMATS, -1} }, |
||
246 |
[SECTION_ID_STREAMS] = { SECTION_ID_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM, -1 } }, |
||
247 |
[SECTION_ID_STREAM] = { SECTION_ID_STREAM, "stream", 0, { SECTION_ID_STREAM_DISPOSITION, SECTION_ID_STREAM_TAGS, SECTION_ID_STREAM_SIDE_DATA_LIST, -1 } }, |
||
248 |
[SECTION_ID_STREAM_DISPOSITION] = { SECTION_ID_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_disposition" }, |
||
249 |
[SECTION_ID_STREAM_TAGS] = { SECTION_ID_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_tags" }, |
||
250 |
[SECTION_ID_STREAM_SIDE_DATA_LIST] ={ SECTION_ID_STREAM_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "stream_side_data_list" }, |
||
251 |
[SECTION_ID_STREAM_SIDE_DATA] = { SECTION_ID_STREAM_SIDE_DATA, "side_data", 0, { -1 } }, |
||
252 |
[SECTION_ID_SUBTITLE] = { SECTION_ID_SUBTITLE, "subtitle", 0, { -1 } }, |
||
253 |
}; |
||
254 |
|||
255 |
static const OptionDef *options; |
||
256 |
|||
257 |
/* FFprobe context */ |
||
258 |
static const char *input_filename; |
||
259 |
static const char *print_input_filename; |
||
260 |
static AVInputFormat *iformat = NULL; |
||
261 |
|||
262 |
static struct AVHashContext *hash; |
||
263 |
|||
264 |
static const struct { |
||
265 |
double bin_val; |
||
266 |
double dec_val; |
||
267 |
const char *bin_str; |
||
268 |
const char *dec_str; |
||
269 |
} si_prefixes[] = { |
||
270 |
{ 1.0, 1.0, "", "" }, |
||
271 |
{ 1.024e3, 1e3, "Ki", "K" }, |
||
272 |
{ 1.048576e6, 1e6, "Mi", "M" }, |
||
273 |
{ 1.073741824e9, 1e9, "Gi", "G" }, |
||
274 |
{ 1.099511627776e12, 1e12, "Ti", "T" }, |
||
275 |
{ 1.125899906842624e15, 1e15, "Pi", "P" }, |
||
276 |
}; |
||
277 |
|||
278 |
static const char unit_second_str[] = "s" ; |
||
279 |
static const char unit_hertz_str[] = "Hz" ; |
||
280 |
static const char unit_byte_str[] = "byte" ; |
||
281 |
static const char unit_bit_per_second_str[] = "bit/s"; |
||
282 |
|||
283 |
static int nb_streams; |
||
284 |
static uint64_t *nb_streams_packets; |
||
285 |
static uint64_t *nb_streams_frames; |
||
286 |
static int *selected_streams; |
||
287 |
|||
288 |
#if HAVE_THREADS |
||
289 |
pthread_mutex_t log_mutex; |
||
290 |
#endif |
||
291 |
typedef struct LogBuffer { |
||
292 |
char *context_name; |
||
293 |
int log_level; |
||
294 |
char *log_message; |
||
295 |
AVClassCategory category; |
||
296 |
char *parent_name; |
||
297 |
AVClassCategory parent_category; |
||
298 |
}LogBuffer; |
||
299 |
|||
300 |
static LogBuffer *log_buffer; |
||
301 |
static int log_buffer_size; |
||
302 |
|||
303 |
static void log_callback(void *ptr, int level, const char *fmt, va_list vl) |
||
304 |
{ |
||
305 |
AVClass* avc = ptr ? *(AVClass **) ptr : NULL; |
||
306 |
va_list vl2; |
||
307 |
char line[1024]; |
||
308 |
static int print_prefix = 1; |
||
309 |
void *new_log_buffer; |
||
310 |
|||
311 |
va_copy(vl2, vl); |
||
312 |
av_log_default_callback(ptr, level, fmt, vl); |
||
313 |
av_log_format_line(ptr, level, fmt, vl2, line, sizeof(line), &print_prefix); |
||
314 |
va_end(vl2); |
||
315 |
|||
316 |
#if HAVE_THREADS |
||
317 |
pthread_mutex_lock(&log_mutex); |
||
318 |
|||
319 |
new_log_buffer = av_realloc_array(log_buffer, log_buffer_size + 1, sizeof(*log_buffer)); |
||
320 |
if (new_log_buffer) { |
||
321 |
char *msg; |
||
322 |
int i; |
||
323 |
|||
324 |
log_buffer = new_log_buffer; |
||
325 |
memset(&log_buffer[log_buffer_size], 0, sizeof(log_buffer[log_buffer_size])); |
||
326 |
log_buffer[log_buffer_size].context_name= avc ? av_strdup(avc->item_name(ptr)) : NULL; |
||
327 |
if (avc) { |
||
328 |
if (avc->get_category) log_buffer[log_buffer_size].category = avc->get_category(ptr); |
||
329 |
else log_buffer[log_buffer_size].category = avc->category; |
||
330 |
} |
||
331 |
log_buffer[log_buffer_size].log_level = level; |
||
332 |
msg = log_buffer[log_buffer_size].log_message = av_strdup(line); |
||
333 |
for (i=strlen(msg) - 1; i>=0 && msg[i] == '\n'; i--) { |
||
334 |
msg[i] = 0; |
||
335 |
} |
||
336 |
if (avc && avc->parent_log_context_offset) { |
||
337 |
AVClass** parent = *(AVClass ***) (((uint8_t *) ptr) + |
||
338 |
avc->parent_log_context_offset); |
||
339 |
if (parent && *parent) { |
||
340 |
log_buffer[log_buffer_size].parent_name = av_strdup((*parent)->item_name(parent)); |
||
341 |
log_buffer[log_buffer_size].parent_category = |
||
342 |
(*parent)->get_category ? (*parent)->get_category(parent) :(*parent)->category; |
||
343 |
} |
||
344 |
} |
||
345 |
log_buffer_size ++; |
||
346 |
} |
||
347 |
|||
348 |
pthread_mutex_unlock(&log_mutex); |
||
349 |
#endif |
||
350 |
} |
||
351 |
|||
352 |
static void ffprobe_cleanup(int ret) |
||
353 |
{ |
||
354 |
int i; |
||
355 |
for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) |
||
356 |
av_dict_free(&(sections[i].entries_to_show)); |
||
357 |
|||
358 |
#if HAVE_THREADS |
||
359 |
pthread_mutex_destroy(&log_mutex); |
||
360 |
#endif |
||
361 |
} |
||
362 |
|||
363 |
struct unit_value { |
||
364 |
union { double d; long long int i; } val; |
||
365 |
const char *unit; |
||
366 |
}; |
||
367 |
|||
368 |
29292 |
static char *value_string(char *buf, int buf_size, struct unit_value uv) |
|
369 |
{ |
||
370 |
double vald; |
||
371 |
long long int vali; |
||
372 |
29292 |
int show_float = 0; |
|
373 |
|||
374 |
✓✓ | 29292 |
if (uv.unit == unit_second_str) { |
375 |
22539 |
vald = uv.val.d; |
|
376 |
22539 |
show_float = 1; |
|
377 |
} else { |
||
378 |
6753 |
vald = vali = uv.val.i; |
|
379 |
} |
||
380 |
|||
381 |
✓✓✗✓ |
29292 |
if (uv.unit == unit_second_str && use_value_sexagesimal_format) { |
382 |
double secs; |
||
383 |
int hours, mins; |
||
384 |
secs = vald; |
||
385 |
mins = (int)secs / 60; |
||
386 |
secs = secs - mins * 60; |
||
387 |
hours = mins / 60; |
||
388 |
mins %= 60; |
||
389 |
snprintf(buf, buf_size, "%d:%02d:%09.6f", hours, mins, secs); |
||
390 |
} else { |
||
391 |
29292 |
const char *prefix_string = ""; |
|
392 |
|||
393 |
✗✓✗✗ |
29292 |
if (use_value_prefix && vald > 1) { |
394 |
long long int index; |
||
395 |
|||
396 |
if (uv.unit == unit_byte_str && use_byte_value_binary_prefix) { |
||
397 |
index = (long long int) (log2(vald)) / 10; |
||
398 |
index = av_clip(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1); |
||
399 |
vald /= si_prefixes[index].bin_val; |
||
400 |
prefix_string = si_prefixes[index].bin_str; |
||
401 |
} else { |
||
402 |
index = (long long int) (log10(vald)) / 3; |
||
403 |
index = av_clip(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1); |
||
404 |
vald /= si_prefixes[index].dec_val; |
||
405 |
prefix_string = si_prefixes[index].dec_str; |
||
406 |
} |
||
407 |
vali = vald; |
||
408 |
} |
||
409 |
|||
410 |
✓✓✗✓ ✗✗ |
29292 |
if (show_float || (use_value_prefix && vald != (long long int)vald)) |
411 |
22539 |
snprintf(buf, buf_size, "%f", vald); |
|
412 |
else |
||
413 |
6753 |
snprintf(buf, buf_size, "%lld", vali); |
|
414 |
✓✗✗✓ |
29292 |
av_strlcatf(buf, buf_size, "%s%s%s", *prefix_string || show_value_unit ? " " : "", |
415 |
✗✓ | 29292 |
prefix_string, show_value_unit ? uv.unit : ""); |
416 |
} |
||
417 |
|||
418 |
29292 |
return buf; |
|
419 |
} |
||
420 |
|||
421 |
/* WRITERS API */ |
||
422 |
|||
423 |
typedef struct WriterContext WriterContext; |
||
424 |
|||
425 |
#define WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS 1 |
||
426 |
#define WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER 2 |
||
427 |
|||
428 |
typedef enum { |
||
429 |
WRITER_STRING_VALIDATION_FAIL, |
||
430 |
WRITER_STRING_VALIDATION_REPLACE, |
||
431 |
WRITER_STRING_VALIDATION_IGNORE, |
||
432 |
WRITER_STRING_VALIDATION_NB |
||
433 |
} StringValidation; |
||
434 |
|||
435 |
typedef struct Writer { |
||
436 |
const AVClass *priv_class; ///< private class of the writer, if any |
||
437 |
int priv_size; ///< private size for the writer context |
||
438 |
const char *name; |
||
439 |
|||
440 |
int (*init) (WriterContext *wctx); |
||
441 |
void (*uninit)(WriterContext *wctx); |
||
442 |
|||
443 |
void (*print_section_header)(WriterContext *wctx); |
||
444 |
void (*print_section_footer)(WriterContext *wctx); |
||
445 |
void (*print_integer) (WriterContext *wctx, const char *, long long int); |
||
446 |
void (*print_rational) (WriterContext *wctx, AVRational *q, char *sep); |
||
447 |
void (*print_string) (WriterContext *wctx, const char *, const char *); |
||
448 |
int flags; ///< a combination or WRITER_FLAG_* |
||
449 |
} Writer; |
||
450 |
|||
451 |
#define SECTION_MAX_NB_LEVELS 10 |
||
452 |
|||
453 |
struct WriterContext { |
||
454 |
const AVClass *class; ///< class of the writer |
||
455 |
const Writer *writer; ///< the Writer of which this is an instance |
||
456 |
char *name; ///< name of this writer instance |
||
457 |
void *priv; ///< private data for use by the filter |
||
458 |
|||
459 |
const struct section *sections; ///< array containing all sections |
||
460 |
int nb_sections; ///< number of sections |
||
461 |
|||
462 |
int level; ///< current level, starting from 0 |
||
463 |
|||
464 |
/** number of the item printed in the given section, starting from 0 */ |
||
465 |
unsigned int nb_item[SECTION_MAX_NB_LEVELS]; |
||
466 |
|||
467 |
/** section per each level */ |
||
468 |
const struct section *section[SECTION_MAX_NB_LEVELS]; |
||
469 |
AVBPrint section_pbuf[SECTION_MAX_NB_LEVELS]; ///< generic print buffer dedicated to each section, |
||
470 |
/// used by various writers |
||
471 |
|||
472 |
unsigned int nb_section_packet; ///< number of the packet section in case we are in "packets_and_frames" section |
||
473 |
unsigned int nb_section_frame; ///< number of the frame section in case we are in "packets_and_frames" section |
||
474 |
unsigned int nb_section_packet_frame; ///< nb_section_packet or nb_section_frame according if is_packets_and_frames |
||
475 |
|||
476 |
int string_validation; |
||
477 |
char *string_validation_replacement; |
||
478 |
unsigned int string_validation_utf8_flags; |
||
479 |
}; |
||
480 |
|||
481 |
static const char *writer_get_name(void *p) |
||
482 |
{ |
||
483 |
WriterContext *wctx = p; |
||
484 |
return wctx->writer->name; |
||
485 |
} |
||
486 |
|||
487 |
#define OFFSET(x) offsetof(WriterContext, x) |
||
488 |
|||
489 |
static const AVOption writer_options[] = { |
||
490 |
{ "string_validation", "set string validation mode", |
||
491 |
OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = "sv" }, |
||
492 |
{ "sv", "set string validation mode", |
||
493 |
OFFSET(string_validation), AV_OPT_TYPE_INT, {.i64=WRITER_STRING_VALIDATION_REPLACE}, 0, WRITER_STRING_VALIDATION_NB-1, .unit = "sv" }, |
||
494 |
{ "ignore", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_IGNORE}, .unit = "sv" }, |
||
495 |
{ "replace", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_REPLACE}, .unit = "sv" }, |
||
496 |
{ "fail", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = WRITER_STRING_VALIDATION_FAIL}, .unit = "sv" }, |
||
497 |
{ "string_validation_replacement", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str=""}}, |
||
498 |
{ "svr", "set string validation replacement string", OFFSET(string_validation_replacement), AV_OPT_TYPE_STRING, {.str="\xEF\xBF\xBD"}}, |
||
499 |
{ NULL } |
||
500 |
}; |
||
501 |
|||
502 |
26 |
static void *writer_child_next(void *obj, void *prev) |
|
503 |
{ |
||
504 |
26 |
WriterContext *ctx = obj; |
|
505 |
✓✗✓✗ ✓✗✓✗ |
26 |
if (!prev && ctx->writer && ctx->writer->priv_class && ctx->priv) |
506 |
26 |
return ctx->priv; |
|
507 |
return NULL; |
||
508 |
} |
||
509 |
|||
510 |
static const AVClass writer_class = { |
||
511 |
.class_name = "Writer", |
||
512 |
.item_name = writer_get_name, |
||
513 |
.option = writer_options, |
||
514 |
.version = LIBAVUTIL_VERSION_INT, |
||
515 |
.child_next = writer_child_next, |
||
516 |
}; |
||
517 |
|||
518 |
76 |
static void writer_close(WriterContext **wctx) |
|
519 |
{ |
||
520 |
int i; |
||
521 |
|||
522 |
✗✓ | 76 |
if (!*wctx) |
523 |
return; |
||
524 |
|||
525 |
✗✓ | 76 |
if ((*wctx)->writer->uninit) |
526 |
(*wctx)->writer->uninit(*wctx); |
||
527 |
✓✓ | 836 |
for (i = 0; i < SECTION_MAX_NB_LEVELS; i++) |
528 |
760 |
av_bprint_finalize(&(*wctx)->section_pbuf[i], NULL); |
|
529 |
✓✗ | 76 |
if ((*wctx)->writer->priv_class) |
530 |
76 |
av_opt_free((*wctx)->priv); |
|
531 |
76 |
av_freep(&((*wctx)->priv)); |
|
532 |
76 |
av_opt_free(*wctx); |
|
533 |
76 |
av_freep(wctx); |
|
534 |
} |
||
535 |
|||
536 |
static void bprint_bytes(AVBPrint *bp, const uint8_t *ubuf, size_t ubuf_size) |
||
537 |
{ |
||
538 |
int i; |
||
539 |
av_bprintf(bp, "0X"); |
||
540 |
for (i = 0; i < ubuf_size; i++) |
||
541 |
av_bprintf(bp, "%02X", ubuf[i]); |
||
542 |
} |
||
543 |
|||
544 |
|||
545 |
76 |
static int writer_open(WriterContext **wctx, const Writer *writer, const char *args, |
|
546 |
const struct section *sections, int nb_sections) |
||
547 |
{ |
||
548 |
76 |
int i, ret = 0; |
|
549 |
|||
550 |
✗✓ | 76 |
if (!(*wctx = av_mallocz(sizeof(WriterContext)))) { |
551 |
ret = AVERROR(ENOMEM); |
||
552 |
goto fail; |
||
553 |
} |
||
554 |
|||
555 |
✗✓ | 76 |
if (!((*wctx)->priv = av_mallocz(writer->priv_size))) { |
556 |
ret = AVERROR(ENOMEM); |
||
557 |
goto fail; |
||
558 |
} |
||
559 |
|||
560 |
76 |
(*wctx)->class = &writer_class; |
|
561 |
76 |
(*wctx)->writer = writer; |
|
562 |
76 |
(*wctx)->level = -1; |
|
563 |
76 |
(*wctx)->sections = sections; |
|
564 |
76 |
(*wctx)->nb_sections = nb_sections; |
|
565 |
|||
566 |
76 |
av_opt_set_defaults(*wctx); |
|
567 |
|||
568 |
✓✗ | 76 |
if (writer->priv_class) { |
569 |
76 |
void *priv_ctx = (*wctx)->priv; |
|
570 |
76 |
*((const AVClass **)priv_ctx) = writer->priv_class; |
|
571 |
76 |
av_opt_set_defaults(priv_ctx); |
|
572 |
} |
||
573 |
|||
574 |
/* convert options to dictionary */ |
||
575 |
✓✓ | 76 |
if (args) { |
576 |
19 |
AVDictionary *opts = NULL; |
|
577 |
19 |
AVDictionaryEntry *opt = NULL; |
|
578 |
|||
579 |
✗✓ | 19 |
if ((ret = av_dict_parse_string(&opts, args, "=", ":", 0)) < 0) { |
580 |
av_log(*wctx, AV_LOG_ERROR, "Failed to parse option string '%s' provided to writer context\n", args); |
||
581 |
av_dict_free(&opts); |
||
582 |
goto fail; |
||
583 |
} |
||
584 |
|||
585 |
✓✓ | 45 |
while ((opt = av_dict_get(opts, "", opt, AV_DICT_IGNORE_SUFFIX))) { |
586 |
✗✓ | 26 |
if ((ret = av_opt_set(*wctx, opt->key, opt->value, AV_OPT_SEARCH_CHILDREN)) < 0) { |
587 |
av_log(*wctx, AV_LOG_ERROR, "Failed to set option '%s' with value '%s' provided to writer context\n", |
||
588 |
opt->key, opt->value); |
||
589 |
av_dict_free(&opts); |
||
590 |
goto fail; |
||
591 |
} |
||
592 |
} |
||
593 |
|||
594 |
19 |
av_dict_free(&opts); |
|
595 |
} |
||
596 |
|||
597 |
/* validate replace string */ |
||
598 |
{ |
||
599 |
76 |
const uint8_t *p = (*wctx)->string_validation_replacement; |
|
600 |
76 |
const uint8_t *endp = p + strlen(p); |
|
601 |
✓✓ | 152 |
while (*p) { |
602 |
76 |
const uint8_t *p0 = p; |
|
603 |
int32_t code; |
||
604 |
76 |
ret = av_utf8_decode(&code, &p, endp, (*wctx)->string_validation_utf8_flags); |
|
605 |
✗✓ | 76 |
if (ret < 0) { |
606 |
AVBPrint bp; |
||
607 |
av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); |
||
608 |
bprint_bytes(&bp, p0, p-p0), |
||
609 |
av_log(wctx, AV_LOG_ERROR, |
||
610 |
"Invalid UTF8 sequence %s found in string validation replace '%s'\n", |
||
611 |
bp.str, (*wctx)->string_validation_replacement); |
||
612 |
return ret; |
||
613 |
} |
||
614 |
} |
||
615 |
} |
||
616 |
|||
617 |
✓✓ | 836 |
for (i = 0; i < SECTION_MAX_NB_LEVELS; i++) |
618 |
760 |
av_bprint_init(&(*wctx)->section_pbuf[i], 1, AV_BPRINT_SIZE_UNLIMITED); |
|
619 |
|||
620 |
✓✓ | 76 |
if ((*wctx)->writer->init) |
621 |
32 |
ret = (*wctx)->writer->init(*wctx); |
|
622 |
✗✓ | 76 |
if (ret < 0) |
623 |
goto fail; |
||
624 |
|||
625 |
76 |
return 0; |
|
626 |
|||
627 |
fail: |
||
628 |
writer_close(wctx); |
||
629 |
return ret; |
||
630 |
} |
||
631 |
|||
632 |
8155 |
static inline void writer_print_section_header(WriterContext *wctx, |
|
633 |
int section_id) |
||
634 |
{ |
||
635 |
int parent_section_id; |
||
636 |
8155 |
wctx->level++; |
|
637 |
✗✓ | 8155 |
av_assert0(wctx->level < SECTION_MAX_NB_LEVELS); |
638 |
16310 |
parent_section_id = wctx->level ? |
|
639 |
✓✓ | 8155 |
(wctx->section[wctx->level-1])->id : SECTION_ID_NONE; |
640 |
|||
641 |
8155 |
wctx->nb_item[wctx->level] = 0; |
|
642 |
8155 |
wctx->section[wctx->level] = &wctx->sections[section_id]; |
|
643 |
|||
644 |
✓✓ | 8155 |
if (section_id == SECTION_ID_PACKETS_AND_FRAMES) { |
645 |
4 |
wctx->nb_section_packet = wctx->nb_section_frame = |
|
646 |
4 |
wctx->nb_section_packet_frame = 0; |
|
647 |
✓✓ | 8151 |
} else if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) { |
648 |
112 |
wctx->nb_section_packet_frame = section_id == SECTION_ID_PACKET ? |
|
649 |
✓✓ | 112 |
wctx->nb_section_packet : wctx->nb_section_frame; |
650 |
} |
||
651 |
|||
652 |
✓✗ | 8155 |
if (wctx->writer->print_section_header) |
653 |
8155 |
wctx->writer->print_section_header(wctx); |
|
654 |
8155 |
} |
|
655 |
|||
656 |
8155 |
static inline void writer_print_section_footer(WriterContext *wctx) |
|
657 |
{ |
||
658 |
8155 |
int section_id = wctx->section[wctx->level]->id; |
|
659 |
16310 |
int parent_section_id = wctx->level ? |
|
660 |
✓✓ | 8155 |
wctx->section[wctx->level-1]->id : SECTION_ID_NONE; |
661 |
|||
662 |
✓✓ | 8155 |
if (parent_section_id != SECTION_ID_NONE) |
663 |
8079 |
wctx->nb_item[wctx->level-1]++; |
|
664 |
✓✓ | 8155 |
if (parent_section_id == SECTION_ID_PACKETS_AND_FRAMES) { |
665 |
✓✓ | 112 |
if (section_id == SECTION_ID_PACKET) wctx->nb_section_packet++; |
666 |
56 |
else wctx->nb_section_frame++; |
|
667 |
} |
||
668 |
✓✓ | 8155 |
if (wctx->writer->print_section_footer) |
669 |
8071 |
wctx->writer->print_section_footer(wctx); |
|
670 |
8155 |
wctx->level--; |
|
671 |
8155 |
} |
|
672 |
|||
673 |
41635 |
static inline void writer_print_integer(WriterContext *wctx, |
|
674 |
const char *key, long long int val) |
||
675 |
{ |
||
676 |
41635 |
const struct section *section = wctx->section[wctx->level]; |
|
677 |
|||
678 |
✓✓✓✓ |
41635 |
if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) { |
679 |
27079 |
wctx->writer->print_integer(wctx, key, val); |
|
680 |
27079 |
wctx->nb_item[wctx->level]++; |
|
681 |
} |
||
682 |
41635 |
} |
|
683 |
|||
684 |
4996 |
static inline int validate_string(WriterContext *wctx, char **dstp, const char *src) |
|
685 |
{ |
||
686 |
const uint8_t *p, *endp; |
||
687 |
AVBPrint dstbuf; |
||
688 |
4996 |
int invalid_chars_nb = 0, ret = 0; |
|
689 |
|||
690 |
4996 |
av_bprint_init(&dstbuf, 0, AV_BPRINT_SIZE_UNLIMITED); |
|
691 |
|||
692 |
4996 |
endp = src + strlen(src); |
|
693 |
✓✓ | 84307 |
for (p = (uint8_t *)src; *p;) { |
694 |
uint32_t code; |
||
695 |
79311 |
int invalid = 0; |
|
696 |
79311 |
const uint8_t *p0 = p; |
|
697 |
|||
698 |
✗✓ | 79311 |
if (av_utf8_decode(&code, &p, endp, wctx->string_validation_utf8_flags) < 0) { |
699 |
AVBPrint bp; |
||
700 |
av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); |
||
701 |
bprint_bytes(&bp, p0, p-p0); |
||
702 |
av_log(wctx, AV_LOG_DEBUG, |
||
703 |
"Invalid UTF-8 sequence %s found in string '%s'\n", bp.str, src); |
||
704 |
invalid = 1; |
||
705 |
} |
||
706 |
|||
707 |
✓✗ | 79311 |
if (invalid) { |
708 |
invalid_chars_nb++; |
||
709 |
|||
710 |
switch (wctx->string_validation) { |
||
711 |
case WRITER_STRING_VALIDATION_FAIL: |
||
712 |
av_log(wctx, AV_LOG_ERROR, |
||
713 |
"Invalid UTF-8 sequence found in string '%s'\n", src); |
||
714 |
ret = AVERROR_INVALIDDATA; |
||
715 |
goto end; |
||
716 |
break; |
||
717 |
|||
718 |
case WRITER_STRING_VALIDATION_REPLACE: |
||
719 |
av_bprintf(&dstbuf, "%s", wctx->string_validation_replacement); |
||
720 |
break; |
||
721 |
} |
||
722 |
79311 |
} |
|
723 |
|||
724 |
✗✓✗✗ |
79311 |
if (!invalid || wctx->string_validation == WRITER_STRING_VALIDATION_IGNORE) |
725 |
79311 |
av_bprint_append_data(&dstbuf, p0, p-p0); |
|
726 |
} |
||
727 |
|||
728 |
✓✗✗✗ |
4996 |
if (invalid_chars_nb && wctx->string_validation == WRITER_STRING_VALIDATION_REPLACE) { |
729 |
av_log(wctx, AV_LOG_WARNING, |
||
730 |
"%d invalid UTF-8 sequence(s) found in string '%s', replaced with '%s'\n", |
||
731 |
invalid_chars_nb, src, wctx->string_validation_replacement); |
||
732 |
} |
||
733 |
|||
734 |
4996 |
end: |
|
735 |
4996 |
av_bprint_finalize(&dstbuf, dstp); |
|
736 |
4996 |
return ret; |
|
737 |
} |
||
738 |
|||
739 |
#define PRINT_STRING_OPT 1 |
||
740 |
#define PRINT_STRING_VALIDATE 2 |
||
741 |
|||
742 |
67920 |
static inline int writer_print_string(WriterContext *wctx, |
|
743 |
const char *key, const char *val, int flags) |
||
744 |
{ |
||
745 |
67920 |
const struct section *section = wctx->section[wctx->level]; |
|
746 |
67920 |
int ret = 0; |
|
747 |
|||
748 |
✓✓ | 67920 |
if ((flags & PRINT_STRING_OPT) |
749 |
✓✓ | 11540 |
&& !(wctx->writer->flags & WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS)) |
750 |
224 |
return 0; |
|
751 |
|||
752 |
✓✓✓✓ |
67696 |
if (section->show_all_entries || av_dict_get(section->entries_to_show, key, NULL, 0)) { |
753 |
✓✓ | 24901 |
if (flags & PRINT_STRING_VALIDATE) { |
754 |
2498 |
char *key1 = NULL, *val1 = NULL; |
|
755 |
2498 |
ret = validate_string(wctx, &key1, key); |
|
756 |
✗✓ | 2498 |
if (ret < 0) goto end; |
757 |
2498 |
ret = validate_string(wctx, &val1, val); |
|
758 |
✗✓ | 2498 |
if (ret < 0) goto end; |
759 |
2498 |
wctx->writer->print_string(wctx, key1, val1); |
|
760 |
2498 |
end: |
|
761 |
✗✓ | 2498 |
if (ret < 0) { |
762 |
av_log(wctx, AV_LOG_ERROR, |
||
763 |
"Invalid key=value string combination %s=%s in section %s\n", |
||
764 |
key, val, section->unique_name); |
||
765 |
} |
||
766 |
2498 |
av_free(key1); |
|
767 |
2498 |
av_free(val1); |
|
768 |
} else { |
||
769 |
22403 |
wctx->writer->print_string(wctx, key, val); |
|
770 |
} |
||
771 |
|||
772 |
24901 |
wctx->nb_item[wctx->level]++; |
|
773 |
} |
||
774 |
|||
775 |
67696 |
return ret; |
|
776 |
} |
||
777 |
|||
778 |
918 |
static inline void writer_print_rational(WriterContext *wctx, |
|
779 |
const char *key, AVRational q, char sep) |
||
780 |
{ |
||
781 |
AVBPrint buf; |
||
782 |
918 |
av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC); |
|
783 |
918 |
av_bprintf(&buf, "%d%c%d", q.num, sep, q.den); |
|
784 |
918 |
writer_print_string(wctx, key, buf.str, 0); |
|
785 |
918 |
} |
|
786 |
|||
787 |
26692 |
static void writer_print_time(WriterContext *wctx, const char *key, |
|
788 |
int64_t ts, const AVRational *time_base, int is_duration) |
||
789 |
{ |
||
790 |
char buf[128]; |
||
791 |
|||
792 |
✓✓✓✓ ✓✓✓✓ |
26692 |
if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) { |
793 |
4153 |
writer_print_string(wctx, key, "N/A", PRINT_STRING_OPT); |
|
794 |
} else { |
||
795 |
22539 |
double d = ts * av_q2d(*time_base); |
|
796 |
struct unit_value uv; |
||
797 |
22539 |
uv.val.d = d; |
|
798 |
22539 |
uv.unit = unit_second_str; |
|
799 |
22539 |
value_string(buf, sizeof(buf), uv); |
|
800 |
22539 |
writer_print_string(wctx, key, buf, 0); |
|
801 |
} |
||
802 |
26692 |
} |
|
803 |
|||
804 |
26626 |
static void writer_print_ts(WriterContext *wctx, const char *key, int64_t ts, int is_duration) |
|
805 |
{ |
||
806 |
✓✓✓✓ ✓✓✓✓ |
26626 |
if ((!is_duration && ts == AV_NOPTS_VALUE) || (is_duration && ts == 0)) { |
807 |
4152 |
writer_print_string(wctx, key, "N/A", PRINT_STRING_OPT); |
|
808 |
} else { |
||
809 |
22474 |
writer_print_integer(wctx, key, ts); |
|
810 |
} |
||
811 |
26626 |
} |
|
812 |
|||
813 |
static void writer_print_data(WriterContext *wctx, const char *name, |
||
814 |
uint8_t *data, int size) |
||
815 |
{ |
||
816 |
AVBPrint bp; |
||
817 |
int offset = 0, l, i; |
||
818 |
|||
819 |
av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); |
||
820 |
av_bprintf(&bp, "\n"); |
||
821 |
while (size) { |
||
822 |
av_bprintf(&bp, "%08x: ", offset); |
||
823 |
l = FFMIN(size, 16); |
||
824 |
for (i = 0; i < l; i++) { |
||
825 |
av_bprintf(&bp, "%02x", data[i]); |
||
826 |
if (i & 1) |
||
827 |
av_bprintf(&bp, " "); |
||
828 |
} |
||
829 |
av_bprint_chars(&bp, ' ', 41 - 2 * i - i / 2); |
||
830 |
for (i = 0; i < l; i++) |
||
831 |
av_bprint_chars(&bp, data[i] - 32U < 95 ? data[i] : '.', 1); |
||
832 |
av_bprintf(&bp, "\n"); |
||
833 |
offset += l; |
||
834 |
data += l; |
||
835 |
size -= l; |
||
836 |
} |
||
837 |
writer_print_string(wctx, name, bp.str, 0); |
||
838 |
av_bprint_finalize(&bp, NULL); |
||
839 |
} |
||
840 |
|||
841 |
3674 |
static void writer_print_data_hash(WriterContext *wctx, const char *name, |
|
842 |
uint8_t *data, int size) |
||
843 |
{ |
||
844 |
3674 |
char *p, buf[AV_HASH_MAX_SIZE * 2 + 64] = { 0 }; |
|
845 |
|||
846 |
✓✓ | 3674 |
if (!hash) |
847 |
3670 |
return; |
|
848 |
4 |
av_hash_init(hash); |
|
849 |
4 |
av_hash_update(hash, data, size); |
|
850 |
4 |
snprintf(buf, sizeof(buf), "%s:", av_hash_get_name(hash)); |
|
851 |
4 |
p = buf + strlen(buf); |
|
852 |
4 |
av_hash_final_hex(hash, p, buf + sizeof(buf) - p); |
|
853 |
4 |
writer_print_string(wctx, name, buf, 0); |
|
854 |
} |
||
855 |
|||
856 |
2 |
static void writer_print_integers(WriterContext *wctx, const char *name, |
|
857 |
uint8_t *data, int size, const char *format, |
||
858 |
int columns, int bytes, int offset_add) |
||
859 |
{ |
||
860 |
AVBPrint bp; |
||
861 |
2 |
int offset = 0, l, i; |
|
862 |
|||
863 |
2 |
av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); |
|
864 |
2 |
av_bprintf(&bp, "\n"); |
|
865 |
✓✓ | 8 |
while (size) { |
866 |
6 |
av_bprintf(&bp, "%08x: ", offset); |
|
867 |
6 |
l = FFMIN(size, columns); |
|
868 |
✓✓ | 24 |
for (i = 0; i < l; i++) { |
869 |
✗✓ | 18 |
if (bytes == 1) av_bprintf(&bp, format, *data); |
870 |
✗✓ | 18 |
else if (bytes == 2) av_bprintf(&bp, format, AV_RN16(data)); |
871 |
✓✗ | 18 |
else if (bytes == 4) av_bprintf(&bp, format, AV_RN32(data)); |
872 |
18 |
data += bytes; |
|
873 |
18 |
size --; |
|
874 |
} |
||
875 |
6 |
av_bprintf(&bp, "\n"); |
|
876 |
6 |
offset += offset_add; |
|
877 |
} |
||
878 |
2 |
writer_print_string(wctx, name, bp.str, 0); |
|
879 |
2 |
av_bprint_finalize(&bp, NULL); |
|
880 |
2 |
} |
|
881 |
|||
882 |
#define MAX_REGISTERED_WRITERS_NB 64 |
||
883 |
|||
884 |
static const Writer *registered_writers[MAX_REGISTERED_WRITERS_NB + 1]; |
||
885 |
|||
886 |
532 |
static int writer_register(const Writer *writer) |
|
887 |
{ |
||
888 |
static int next_registered_writer_idx = 0; |
||
889 |
|||
890 |
✗✓ | 532 |
if (next_registered_writer_idx == MAX_REGISTERED_WRITERS_NB) |
891 |
return AVERROR(ENOMEM); |
||
892 |
|||
893 |
532 |
registered_writers[next_registered_writer_idx++] = writer; |
|
894 |
532 |
return 0; |
|
895 |
} |
||
896 |
|||
897 |
76 |
static const Writer *writer_get_by_name(const char *name) |
|
898 |
{ |
||
899 |
int i; |
||
900 |
|||
901 |
✓✗ | 124 |
for (i = 0; registered_writers[i]; i++) |
902 |
✓✓ | 124 |
if (!strcmp(registered_writers[i]->name, name)) |
903 |
76 |
return registered_writers[i]; |
|
904 |
|||
905 |
return NULL; |
||
906 |
} |
||
907 |
|||
908 |
|||
909 |
/* WRITERS */ |
||
910 |
|||
911 |
#define DEFINE_WRITER_CLASS(name) \ |
||
912 |
static const char *name##_get_name(void *ctx) \ |
||
913 |
{ \ |
||
914 |
return #name ; \ |
||
915 |
} \ |
||
916 |
static const AVClass name##_class = { \ |
||
917 |
.class_name = #name, \ |
||
918 |
.item_name = name##_get_name, \ |
||
919 |
.option = name##_options \ |
||
920 |
} |
||
921 |
|||
922 |
/* Default output */ |
||
923 |
|||
924 |
typedef struct DefaultContext { |
||
925 |
const AVClass *class; |
||
926 |
int nokey; |
||
927 |
int noprint_wrappers; |
||
928 |
int nested_section[SECTION_MAX_NB_LEVELS]; |
||
929 |
} DefaultContext; |
||
930 |
|||
931 |
#undef OFFSET |
||
932 |
#define OFFSET(x) offsetof(DefaultContext, x) |
||
933 |
|||
934 |
static const AVOption default_options[] = { |
||
935 |
{ "noprint_wrappers", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, |
||
936 |
{ "nw", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, |
||
937 |
{ "nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, |
||
938 |
{ "nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, |
||
939 |
{NULL}, |
||
940 |
}; |
||
941 |
|||
942 |
DEFINE_WRITER_CLASS(default); |
||
943 |
|||
944 |
/* lame uppercasing routine, assumes the string is lower case ASCII */ |
||
945 |
2333 |
static inline char *upcase_string(char *dst, size_t dst_size, const char *src) |
|
946 |
{ |
||
947 |
int i; |
||
948 |
✓✓✓✗ |
16982 |
for (i = 0; src[i] && i < dst_size-1; i++) |
949 |
14649 |
dst[i] = av_toupper(src[i]); |
|
950 |
2333 |
dst[i] = 0; |
|
951 |
2333 |
return dst; |
|
952 |
} |
||
953 |
|||
954 |
1418 |
static void default_print_section_header(WriterContext *wctx) |
|
955 |
{ |
||
956 |
1418 |
DefaultContext *def = wctx->priv; |
|
957 |
char buf[32]; |
||
958 |
1418 |
const struct section *section = wctx->section[wctx->level]; |
|
959 |
2836 |
const struct section *parent_section = wctx->level ? |
|
960 |
✓✓ | 1418 |
wctx->section[wctx->level-1] : NULL; |
961 |
|||
962 |
1418 |
av_bprint_clear(&wctx->section_pbuf[wctx->level]); |
|
963 |
✓✓ | 1418 |
if (parent_section && |
964 |
✓✓ | 1375 |
!(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) { |
965 |
281 |
def->nested_section[wctx->level] = 1; |
|
966 |
281 |
av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:", |
|
967 |
281 |
wctx->section_pbuf[wctx->level-1].str, |
|
968 |
upcase_string(buf, sizeof(buf), |
||
969 |
281 |
av_x_if_null(section->element_name, section->name))); |
|
970 |
} |
||
971 |
|||
972 |
✓✓✓✓ |
1418 |
if (def->noprint_wrappers || def->nested_section[wctx->level]) |
973 |
289 |
return; |
|
974 |
|||
975 |
✓✓ | 1129 |
if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) |
976 |
1026 |
printf("[%s]\n", upcase_string(buf, sizeof(buf), section->name)); |
|
977 |
} |
||
978 |
|||
979 |
1418 |
static void default_print_section_footer(WriterContext *wctx) |
|
980 |
{ |
||
981 |
1418 |
DefaultContext *def = wctx->priv; |
|
982 |
1418 |
const struct section *section = wctx->section[wctx->level]; |
|
983 |
char buf[32]; |
||
984 |
|||
985 |
✓✓✓✓ |
1418 |
if (def->noprint_wrappers || def->nested_section[wctx->level]) |
986 |
289 |
return; |
|
987 |
|||
988 |
✓✓ | 1129 |
if (!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) |
989 |
1026 |
printf("[/%s]\n", upcase_string(buf, sizeof(buf), section->name)); |
|
990 |
} |
||
991 |
|||
992 |
8569 |
static void default_print_str(WriterContext *wctx, const char *key, const char *value) |
|
993 |
{ |
||
994 |
8569 |
DefaultContext *def = wctx->priv; |
|
995 |
|||
996 |
✓✓ | 8569 |
if (!def->nokey) |
997 |
8565 |
printf("%s%s=", wctx->section_pbuf[wctx->level].str, key); |
|
998 |
8569 |
printf("%s\n", value); |
|
999 |
8569 |
} |
|
1000 |
|||
1001 |
4048 |
static void default_print_int(WriterContext *wctx, const char *key, long long int value) |
|
1002 |
{ |
||
1003 |
4048 |
DefaultContext *def = wctx->priv; |
|
1004 |
|||
1005 |
✓✗ | 4048 |
if (!def->nokey) |
1006 |
4048 |
printf("%s%s=", wctx->section_pbuf[wctx->level].str, key); |
|
1007 |
4048 |
printf("%lld\n", value); |
|
1008 |
4048 |
} |
|
1009 |
|||
1010 |
static const Writer default_writer = { |
||
1011 |
.name = "default", |
||
1012 |
.priv_size = sizeof(DefaultContext), |
||
1013 |
.print_section_header = default_print_section_header, |
||
1014 |
.print_section_footer = default_print_section_footer, |
||
1015 |
.print_integer = default_print_int, |
||
1016 |
.print_string = default_print_str, |
||
1017 |
.flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS, |
||
1018 |
.priv_class = &default_class, |
||
1019 |
}; |
||
1020 |
|||
1021 |
/* Compact output */ |
||
1022 |
|||
1023 |
/** |
||
1024 |
* Apply C-language-like string escaping. |
||
1025 |
*/ |
||
1026 |
14581 |
static const char *c_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx) |
|
1027 |
{ |
||
1028 |
const char *p; |
||
1029 |
|||
1030 |
✓✓ | 88230 |
for (p = src; *p; p++) { |
1031 |
✗✗✓✗ ✗✓ |
73649 |
switch (*p) { |
1032 |
case '\b': av_bprintf(dst, "%s", "\\b"); break; |
||
1033 |
case '\f': av_bprintf(dst, "%s", "\\f"); break; |
||
1034 |
4 |
case '\n': av_bprintf(dst, "%s", "\\n"); break; |
|
1035 |
case '\r': av_bprintf(dst, "%s", "\\r"); break; |
||
1036 |
case '\\': av_bprintf(dst, "%s", "\\\\"); break; |
||
1037 |
73645 |
default: |
|
1038 |
✗✓ | 73645 |
if (*p == sep) |
1039 |
av_bprint_chars(dst, '\\', 1); |
||
1040 |
73645 |
av_bprint_chars(dst, *p, 1); |
|
1041 |
} |
||
1042 |
} |
||
1043 |
14581 |
return dst->str; |
|
1044 |
} |
||
1045 |
|||
1046 |
/** |
||
1047 |
* Quote fields containing special characters, check RFC4180. |
||
1048 |
*/ |
||
1049 |
395 |
static const char *csv_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx) |
|
1050 |
{ |
||
1051 |
395 |
char meta_chars[] = { sep, '"', '\n', '\r', '\0' }; |
|
1052 |
395 |
int needs_quoting = !!src[strcspn(src, meta_chars)]; |
|
1053 |
|||
1054 |
✓✓ | 395 |
if (needs_quoting) |
1055 |
1 |
av_bprint_chars(dst, '"', 1); |
|
1056 |
|||
1057 |
✓✓ | 2812 |
for (; *src; src++) { |
1058 |
✓✓ | 2417 |
if (*src == '"') |
1059 |
2 |
av_bprint_chars(dst, '"', 1); |
|
1060 |
2417 |
av_bprint_chars(dst, *src, 1); |
|
1061 |
} |
||
1062 |
✓✓ | 395 |
if (needs_quoting) |
1063 |
1 |
av_bprint_chars(dst, '"', 1); |
|
1064 |
395 |
return dst->str; |
|
1065 |
} |
||
1066 |
|||
1067 |
static const char *none_escape_str(AVBPrint *dst, const char *src, const char sep, void *log_ctx) |
||
1068 |
{ |
||
1069 |
return src; |
||
1070 |
} |
||
1071 |
|||
1072 |
typedef struct CompactContext { |
||
1073 |
const AVClass *class; |
||
1074 |
char *item_sep_str; |
||
1075 |
char item_sep; |
||
1076 |
int nokey; |
||
1077 |
int print_section; |
||
1078 |
char *escape_mode_str; |
||
1079 |
const char * (*escape_str)(AVBPrint *dst, const char *src, const char sep, void *log_ctx); |
||
1080 |
int nested_section[SECTION_MAX_NB_LEVELS]; |
||
1081 |
int has_nested_elems[SECTION_MAX_NB_LEVELS]; |
||
1082 |
int terminate_line[SECTION_MAX_NB_LEVELS]; |
||
1083 |
} CompactContext; |
||
1084 |
|||
1085 |
#undef OFFSET |
||
1086 |
#define OFFSET(x) offsetof(CompactContext, x) |
||
1087 |
|||
1088 |
static const AVOption compact_options[]= { |
||
1089 |
{"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, 0, 0 }, |
||
1090 |
{"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str="|"}, 0, 0 }, |
||
1091 |
{"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, |
||
1092 |
{"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, |
||
1093 |
{"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, 0, 0 }, |
||
1094 |
{"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="c"}, 0, 0 }, |
||
1095 |
{"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, |
||
1096 |
{"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, |
||
1097 |
{NULL}, |
||
1098 |
}; |
||
1099 |
|||
1100 |
DEFINE_WRITER_CLASS(compact); |
||
1101 |
|||
1102 |
29 |
static av_cold int compact_init(WriterContext *wctx) |
|
1103 |
{ |
||
1104 |
29 |
CompactContext *compact = wctx->priv; |
|
1105 |
|||
1106 |
✗✓ | 29 |
if (strlen(compact->item_sep_str) != 1) { |
1107 |
av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n", |
||
1108 |
compact->item_sep_str); |
||
1109 |
return AVERROR(EINVAL); |
||
1110 |
} |
||
1111 |
29 |
compact->item_sep = compact->item_sep_str[0]; |
|
1112 |
|||
1113 |
✗✓ | 29 |
if (!strcmp(compact->escape_mode_str, "none")) compact->escape_str = none_escape_str; |
1114 |
✓✓ | 29 |
else if (!strcmp(compact->escape_mode_str, "c" )) compact->escape_str = c_escape_str; |
1115 |
✓✗ | 1 |
else if (!strcmp(compact->escape_mode_str, "csv" )) compact->escape_str = csv_escape_str; |
1116 |
else { |
||
1117 |
av_log(wctx, AV_LOG_ERROR, "Unknown escape mode '%s'\n", compact->escape_mode_str); |
||
1118 |
return AVERROR(EINVAL); |
||
1119 |
} |
||
1120 |
|||
1121 |
29 |
return 0; |
|
1122 |
} |
||
1123 |
|||
1124 |
6569 |
static void compact_print_section_header(WriterContext *wctx) |
|
1125 |
{ |
||
1126 |
6569 |
CompactContext *compact = wctx->priv; |
|
1127 |
6569 |
const struct section *section = wctx->section[wctx->level]; |
|
1128 |
13138 |
const struct section *parent_section = wctx->level ? |
|
1129 |
✓✓ | 6569 |
wctx->section[wctx->level-1] : NULL; |
1130 |
6569 |
compact->terminate_line[wctx->level] = 1; |
|
1131 |
6569 |
compact->has_nested_elems[wctx->level] = 0; |
|
1132 |
|||
1133 |
6569 |
av_bprint_clear(&wctx->section_pbuf[wctx->level]); |
|
1134 |
✓✓✓✓ |
6569 |
if (!(section->flags & SECTION_FLAG_IS_ARRAY) && parent_section && |
1135 |
✓✓ | 6323 |
!(parent_section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) { |
1136 |
462 |
compact->nested_section[wctx->level] = 1; |
|
1137 |
462 |
compact->has_nested_elems[wctx->level-1] = 1; |
|
1138 |
462 |
av_bprintf(&wctx->section_pbuf[wctx->level], "%s%s:", |
|
1139 |
462 |
wctx->section_pbuf[wctx->level-1].str, |
|
1140 |
462 |
(char *)av_x_if_null(section->element_name, section->name)); |
|
1141 |
462 |
wctx->nb_item[wctx->level] = wctx->nb_item[wctx->level-1]; |
|
1142 |
} else { |
||
1143 |
✓✓✓✓ |
6107 |
if (parent_section && compact->has_nested_elems[wctx->level-1] && |
1144 |
✓✗ | 32 |
(section->flags & SECTION_FLAG_IS_ARRAY)) { |
1145 |
32 |
compact->terminate_line[wctx->level-1] = 0; |
|
1146 |
32 |
printf("\n"); |
|
1147 |
} |
||
1148 |
✓✓ | 6107 |
if (compact->print_section && |
1149 |
✓✓ | 4891 |
!(section->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) |
1150 |
4773 |
printf("%s%c", section->name, compact->item_sep); |
|
1151 |
} |
||
1152 |
6569 |
} |
|
1153 |
|||
1154 |
6569 |
static void compact_print_section_footer(WriterContext *wctx) |
|
1155 |
{ |
||
1156 |
6569 |
CompactContext *compact = wctx->priv; |
|
1157 |
|||
1158 |
✓✓ | 6569 |
if (!compact->nested_section[wctx->level] && |
1159 |
✓✓ | 6075 |
compact->terminate_line[wctx->level] && |
1160 |
✓✓ | 6043 |
!(wctx->section[wctx->level]->flags & (SECTION_FLAG_IS_WRAPPER|SECTION_FLAG_IS_ARRAY))) |
1161 |
5829 |
printf("\n"); |
|
1162 |
6569 |
} |
|
1163 |
|||
1164 |
14976 |
static void compact_print_str(WriterContext *wctx, const char *key, const char *value) |
|
1165 |
{ |
||
1166 |
14976 |
CompactContext *compact = wctx->priv; |
|
1167 |
AVBPrint buf; |
||
1168 |
|||
1169 |
✓✓ | 14976 |
if (wctx->nb_item[wctx->level]) printf("%c", compact->item_sep); |
1170 |
✓✓ | 14976 |
if (!compact->nokey) |
1171 |
11416 |
printf("%s%s=", wctx->section_pbuf[wctx->level].str, key); |
|
1172 |
14976 |
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
1173 |
14976 |
printf("%s", compact->escape_str(&buf, value, compact->item_sep, wctx)); |
|
1174 |
14976 |
av_bprint_finalize(&buf, NULL); |
|
1175 |
14976 |
} |
|
1176 |
|||
1177 |
21947 |
static void compact_print_int(WriterContext *wctx, const char *key, long long int value) |
|
1178 |
{ |
||
1179 |
21947 |
CompactContext *compact = wctx->priv; |
|
1180 |
|||
1181 |
✓✓ | 21947 |
if (wctx->nb_item[wctx->level]) printf("%c", compact->item_sep); |
1182 |
✓✓ | 21947 |
if (!compact->nokey) |
1183 |
20284 |
printf("%s%s=", wctx->section_pbuf[wctx->level].str, key); |
|
1184 |
21947 |
printf("%lld", value); |
|
1185 |
21947 |
} |
|
1186 |
|||
1187 |
static const Writer compact_writer = { |
||
1188 |
.name = "compact", |
||
1189 |
.priv_size = sizeof(CompactContext), |
||
1190 |
.init = compact_init, |
||
1191 |
.print_section_header = compact_print_section_header, |
||
1192 |
.print_section_footer = compact_print_section_footer, |
||
1193 |
.print_integer = compact_print_int, |
||
1194 |
.print_string = compact_print_str, |
||
1195 |
.flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS, |
||
1196 |
.priv_class = &compact_class, |
||
1197 |
}; |
||
1198 |
|||
1199 |
/* CSV output */ |
||
1200 |
|||
1201 |
#undef OFFSET |
||
1202 |
#define OFFSET(x) offsetof(CompactContext, x) |
||
1203 |
|||
1204 |
static const AVOption csv_options[] = { |
||
1205 |
{"item_sep", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, 0, 0 }, |
||
1206 |
{"s", "set item separator", OFFSET(item_sep_str), AV_OPT_TYPE_STRING, {.str=","}, 0, 0 }, |
||
1207 |
{"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, |
||
1208 |
{"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, |
||
1209 |
{"escape", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, 0, 0 }, |
||
1210 |
{"e", "set escape mode", OFFSET(escape_mode_str), AV_OPT_TYPE_STRING, {.str="csv"}, 0, 0 }, |
||
1211 |
{"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, |
||
1212 |
{"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, |
||
1213 |
{NULL}, |
||
1214 |
}; |
||
1215 |
|||
1216 |
DEFINE_WRITER_CLASS(csv); |
||
1217 |
|||
1218 |
static const Writer csv_writer = { |
||
1219 |
.name = "csv", |
||
1220 |
.priv_size = sizeof(CompactContext), |
||
1221 |
.init = compact_init, |
||
1222 |
.print_section_header = compact_print_section_header, |
||
1223 |
.print_section_footer = compact_print_section_footer, |
||
1224 |
.print_integer = compact_print_int, |
||
1225 |
.print_string = compact_print_str, |
||
1226 |
.flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS, |
||
1227 |
.priv_class = &csv_class, |
||
1228 |
}; |
||
1229 |
|||
1230 |
/* Flat output */ |
||
1231 |
|||
1232 |
typedef struct FlatContext { |
||
1233 |
const AVClass *class; |
||
1234 |
const char *sep_str; |
||
1235 |
char sep; |
||
1236 |
int hierarchical; |
||
1237 |
} FlatContext; |
||
1238 |
|||
1239 |
#undef OFFSET |
||
1240 |
#define OFFSET(x) offsetof(FlatContext, x) |
||
1241 |
|||
1242 |
static const AVOption flat_options[]= { |
||
1243 |
{"sep_char", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, {.str="."}, 0, 0 }, |
||
1244 |
{"s", "set separator", OFFSET(sep_str), AV_OPT_TYPE_STRING, {.str="."}, 0, 0 }, |
||
1245 |
{"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, |
||
1246 |
{"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, |
||
1247 |
{NULL}, |
||
1248 |
}; |
||
1249 |
|||
1250 |
DEFINE_WRITER_CLASS(flat); |
||
1251 |
|||
1252 |
1 |
static av_cold int flat_init(WriterContext *wctx) |
|
1253 |
{ |
||
1254 |
1 |
FlatContext *flat = wctx->priv; |
|
1255 |
|||
1256 |
✗✓ | 1 |
if (strlen(flat->sep_str) != 1) { |
1257 |
av_log(wctx, AV_LOG_ERROR, "Item separator '%s' specified, but must contain a single character\n", |
||
1258 |
flat->sep_str); |
||
1259 |
return AVERROR(EINVAL); |
||
1260 |
} |
||
1261 |
1 |
flat->sep = flat->sep_str[0]; |
|
1262 |
|||
1263 |
1 |
return 0; |
|
1264 |
} |
||
1265 |
|||
1266 |
395 |
static const char *flat_escape_key_str(AVBPrint *dst, const char *src, const char sep) |
|
1267 |
{ |
||
1268 |
const char *p; |
||
1269 |
|||
1270 |
✓✓ | 5013 |
for (p = src; *p; p++) { |
1271 |
✓✗✓✓ |
4618 |
if (!((*p >= '0' && *p <= '9') || |
1272 |
✓✓✗✓ |
4617 |
(*p >= 'a' && *p <= 'z') || |
1273 |
✓✗✓✓ |
455 |
(*p >= 'A' && *p <= 'Z'))) |
1274 |
454 |
av_bprint_chars(dst, '_', 1); |
|
1275 |
else |
||
1276 |
4164 |
av_bprint_chars(dst, *p, 1); |
|
1277 |
} |
||
1278 |
395 |
return dst->str; |
|
1279 |
} |
||
1280 |
|||
1281 |
395 |
static const char *flat_escape_value_str(AVBPrint *dst, const char *src) |
|
1282 |
{ |
||
1283 |
const char *p; |
||
1284 |
|||
1285 |
✓✓ | 2812 |
for (p = src; *p; p++) { |
1286 |
✗✗✗✓ ✗✗✓ |
2417 |
switch (*p) { |
1287 |
case '\n': av_bprintf(dst, "%s", "\\n"); break; |
||
1288 |
case '\r': av_bprintf(dst, "%s", "\\r"); break; |
||
1289 |
case '\\': av_bprintf(dst, "%s", "\\\\"); break; |
||
1290 |
2 |
case '"': av_bprintf(dst, "%s", "\\\""); break; |
|
1291 |
case '`': av_bprintf(dst, "%s", "\\`"); break; |
||
1292 |
case '$': av_bprintf(dst, "%s", "\\$"); break; |
||
1293 |
2415 |
default: av_bprint_chars(dst, *p, 1); break; |
|
1294 |
} |
||
1295 |
} |
||
1296 |
395 |
return dst->str; |
|
1297 |
} |
||
1298 |
|||
1299 |
42 |
static void flat_print_section_header(WriterContext *wctx) |
|
1300 |
{ |
||
1301 |
42 |
FlatContext *flat = wctx->priv; |
|
1302 |
42 |
AVBPrint *buf = &wctx->section_pbuf[wctx->level]; |
|
1303 |
42 |
const struct section *section = wctx->section[wctx->level]; |
|
1304 |
84 |
const struct section *parent_section = wctx->level ? |
|
1305 |
✓✓ | 42 |
wctx->section[wctx->level-1] : NULL; |
1306 |
|||
1307 |
/* build section header */ |
||
1308 |
42 |
av_bprint_clear(buf); |
|
1309 |
✓✓ | 42 |
if (!parent_section) |
1310 |
1 |
return; |
|
1311 |
41 |
av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str); |
|
1312 |
|||
1313 |
✗✓ | 41 |
if (flat->hierarchical || |
1314 |
!(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) { |
||
1315 |
41 |
av_bprintf(buf, "%s%s", wctx->section[wctx->level]->name, flat->sep_str); |
|
1316 |
|||
1317 |
✓✓ | 41 |
if (parent_section->flags & SECTION_FLAG_IS_ARRAY) { |
1318 |
62 |
int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ? |
|
1319 |
✓✓ | 31 |
wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1]; |
1320 |
31 |
av_bprintf(buf, "%d%s", n, flat->sep_str); |
|
1321 |
} |
||
1322 |
} |
||
1323 |
} |
||
1324 |
|||
1325 |
271 |
static void flat_print_int(WriterContext *wctx, const char *key, long long int value) |
|
1326 |
{ |
||
1327 |
271 |
printf("%s%s=%lld\n", wctx->section_pbuf[wctx->level].str, key, value); |
|
1328 |
271 |
} |
|
1329 |
|||
1330 |
395 |
static void flat_print_str(WriterContext *wctx, const char *key, const char *value) |
|
1331 |
{ |
||
1332 |
395 |
FlatContext *flat = wctx->priv; |
|
1333 |
AVBPrint buf; |
||
1334 |
|||
1335 |
395 |
printf("%s", wctx->section_pbuf[wctx->level].str); |
|
1336 |
395 |
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
1337 |
395 |
printf("%s=", flat_escape_key_str(&buf, key, flat->sep)); |
|
1338 |
395 |
av_bprint_clear(&buf); |
|
1339 |
395 |
printf("\"%s\"\n", flat_escape_value_str(&buf, value)); |
|
1340 |
395 |
av_bprint_finalize(&buf, NULL); |
|
1341 |
395 |
} |
|
1342 |
|||
1343 |
static const Writer flat_writer = { |
||
1344 |
.name = "flat", |
||
1345 |
.priv_size = sizeof(FlatContext), |
||
1346 |
.init = flat_init, |
||
1347 |
.print_section_header = flat_print_section_header, |
||
1348 |
.print_integer = flat_print_int, |
||
1349 |
.print_string = flat_print_str, |
||
1350 |
.flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER, |
||
1351 |
.priv_class = &flat_class, |
||
1352 |
}; |
||
1353 |
|||
1354 |
/* INI format output */ |
||
1355 |
|||
1356 |
typedef struct INIContext { |
||
1357 |
const AVClass *class; |
||
1358 |
int hierarchical; |
||
1359 |
} INIContext; |
||
1360 |
|||
1361 |
#undef OFFSET |
||
1362 |
#define OFFSET(x) offsetof(INIContext, x) |
||
1363 |
|||
1364 |
static const AVOption ini_options[] = { |
||
1365 |
{"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, |
||
1366 |
{"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 }, |
||
1367 |
{NULL}, |
||
1368 |
}; |
||
1369 |
|||
1370 |
DEFINE_WRITER_CLASS(ini); |
||
1371 |
|||
1372 |
790 |
static char *ini_escape_str(AVBPrint *dst, const char *src) |
|
1373 |
{ |
||
1374 |
790 |
int i = 0; |
|
1375 |
790 |
char c = 0; |
|
1376 |
|||
1377 |
✓✓ | 7825 |
while (c = src[i++]) { |
1378 |
✗✗✗✗ ✗✓✓ |
7035 |
switch (c) { |
1379 |
case '\b': av_bprintf(dst, "%s", "\\b"); break; |
||
1380 |
case '\f': av_bprintf(dst, "%s", "\\f"); break; |
||
1381 |
case '\n': av_bprintf(dst, "%s", "\\n"); break; |
||
1382 |
case '\r': av_bprintf(dst, "%s", "\\r"); break; |
||
1383 |
case '\t': av_bprintf(dst, "%s", "\\t"); break; |
||
1384 |
14 |
case '\\': |
|
1385 |
case '#' : |
||
1386 |
case '=' : |
||
1387 |
14 |
case ':' : av_bprint_chars(dst, '\\', 1); |
|
1388 |
7035 |
default: |
|
1389 |
✗✓ | 7035 |
if ((unsigned char)c < 32) |
1390 |
av_bprintf(dst, "\\x00%02x", c & 0xff); |
||
1391 |
else |
||
1392 |
7035 |
av_bprint_chars(dst, c, 1); |
|
1393 |
7035 |
break; |
|
1394 |
} |
||
1395 |
} |
||
1396 |
790 |
return dst->str; |
|
1397 |
} |
||
1398 |
|||
1399 |
42 |
static void ini_print_section_header(WriterContext *wctx) |
|
1400 |
{ |
||
1401 |
42 |
INIContext *ini = wctx->priv; |
|
1402 |
42 |
AVBPrint *buf = &wctx->section_pbuf[wctx->level]; |
|
1403 |
42 |
const struct section *section = wctx->section[wctx->level]; |
|
1404 |
84 |
const struct section *parent_section = wctx->level ? |
|
1405 |
✓✓ | 42 |
wctx->section[wctx->level-1] : NULL; |
1406 |
|||
1407 |
42 |
av_bprint_clear(buf); |
|
1408 |
✓✓ | 42 |
if (!parent_section) { |
1409 |
1 |
printf("# ffprobe output\n\n"); |
|
1410 |
1 |
return; |
|
1411 |
} |
||
1412 |
|||
1413 |
✓✓ | 41 |
if (wctx->nb_item[wctx->level-1]) |
1414 |
38 |
printf("\n"); |
|
1415 |
|||
1416 |
41 |
av_bprintf(buf, "%s", wctx->section_pbuf[wctx->level-1].str); |
|
1417 |
✗✓ | 41 |
if (ini->hierarchical || |
1418 |
!(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) { |
||
1419 |
✓✓ | 41 |
av_bprintf(buf, "%s%s", buf->str[0] ? "." : "", wctx->section[wctx->level]->name); |
1420 |
|||
1421 |
✓✓ | 41 |
if (parent_section->flags & SECTION_FLAG_IS_ARRAY) { |
1422 |
62 |
int n = parent_section->id == SECTION_ID_PACKETS_AND_FRAMES ? |
|
1423 |
✓✓ | 31 |
wctx->nb_section_packet_frame : wctx->nb_item[wctx->level-1]; |
1424 |
31 |
av_bprintf(buf, ".%d", n); |
|
1425 |
} |
||
1426 |
} |
||
1427 |
|||
1428 |
✓✓ | 41 |
if (!(section->flags & (SECTION_FLAG_IS_ARRAY|SECTION_FLAG_IS_WRAPPER))) |
1429 |
39 |
printf("[%s]\n", buf->str); |
|
1430 |
} |
||
1431 |
|||
1432 |
395 |
static void ini_print_str(WriterContext *wctx, const char *key, const char *value) |
|
1433 |
{ |
||
1434 |
AVBPrint buf; |
||
1435 |
|||
1436 |
395 |
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
1437 |
395 |
printf("%s=", ini_escape_str(&buf, key)); |
|
1438 |
395 |
av_bprint_clear(&buf); |
|
1439 |
395 |
printf("%s\n", ini_escape_str(&buf, value)); |
|
1440 |
395 |
av_bprint_finalize(&buf, NULL); |
|
1441 |
395 |
} |
|
1442 |
|||
1443 |
271 |
static void ini_print_int(WriterContext *wctx, const char *key, long long int value) |
|
1444 |
{ |
||
1445 |
271 |
printf("%s=%lld\n", key, value); |
|
1446 |
271 |
} |
|
1447 |
|||
1448 |
static const Writer ini_writer = { |
||
1449 |
.name = "ini", |
||
1450 |
.priv_size = sizeof(INIContext), |
||
1451 |
.print_section_header = ini_print_section_header, |
||
1452 |
.print_integer = ini_print_int, |
||
1453 |
.print_string = ini_print_str, |
||
1454 |
.flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER, |
||
1455 |
.priv_class = &ini_class, |
||
1456 |
}; |
||
1457 |
|||
1458 |
/* JSON output */ |
||
1459 |
|||
1460 |
typedef struct JSONContext { |
||
1461 |
const AVClass *class; |
||
1462 |
int indent_level; |
||
1463 |
int compact; |
||
1464 |
const char *item_sep, *item_start_end; |
||
1465 |
} JSONContext; |
||
1466 |
|||
1467 |
#undef OFFSET |
||
1468 |
#define OFFSET(x) offsetof(JSONContext, x) |
||
1469 |
|||
1470 |
static const AVOption json_options[]= { |
||
1471 |
{ "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, |
||
1472 |
{ "c", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, |
||
1473 |
{ NULL } |
||
1474 |
}; |
||
1475 |
|||
1476 |
DEFINE_WRITER_CLASS(json); |
||
1477 |
|||
1478 |
1 |
static av_cold int json_init(WriterContext *wctx) |
|
1479 |
{ |
||
1480 |
1 |
JSONContext *json = wctx->priv; |
|
1481 |
|||
1482 |
✗✓ | 1 |
json->item_sep = json->compact ? ", " : ",\n"; |
1483 |
✗✓ | 1 |
json->item_start_end = json->compact ? " " : "\n"; |
1484 |
|||
1485 |
1 |
return 0; |
|
1486 |
} |
||
1487 |
|||
1488 |
878 |
static const char *json_escape_str(AVBPrint *dst, const char *src, void *log_ctx) |
|
1489 |
{ |
||
1490 |
static const char json_escape[] = {'"', '\\', '\b', '\f', '\n', '\r', '\t', 0}; |
||
1491 |
static const char json_subst[] = {'"', '\\', 'b', 'f', 'n', 'r', 't', 0}; |
||
1492 |
const char *p; |
||
1493 |
|||
1494 |
✓✓ | 8664 |
for (p = src; *p; p++) { |
1495 |
7786 |
char *s = strchr(json_escape, *p); |
|
1496 |
✓✓ | 7786 |
if (s) { |
1497 |
2 |
av_bprint_chars(dst, '\\', 1); |
|
1498 |
2 |
av_bprint_chars(dst, json_subst[s - json_escape], 1); |
|
1499 |
✗✓ | 7784 |
} else if ((unsigned char)*p < 32) { |
1500 |
av_bprintf(dst, "\\u00%02x", *p & 0xff); |
||
1501 |
} else { |
||
1502 |
7784 |
av_bprint_chars(dst, *p, 1); |
|
1503 |
} |
||
1504 |
} |
||
1505 |
878 |
return dst->str; |
|
1506 |
} |
||
1507 |
|||
1508 |
#define JSON_INDENT() printf("%*c", json->indent_level * 4, ' ') |
||
1509 |
|||
1510 |
42 |
static void json_print_section_header(WriterContext *wctx) |
|
1511 |
{ |
||
1512 |
42 |
JSONContext *json = wctx->priv; |
|
1513 |
AVBPrint buf; |
||
1514 |
42 |
const struct section *section = wctx->section[wctx->level]; |
|
1515 |
84 |
const struct section *parent_section = wctx->level ? |
|
1516 |
✓✓ | 42 |
wctx->section[wctx->level-1] : NULL; |
1517 |
|||
1518 |
✓✓✓✓ |
42 |
if (wctx->level && wctx->nb_item[wctx->level-1]) |
1519 |
38 |
printf(",\n"); |
|
1520 |
|||
1521 |
✓✓ | 42 |
if (section->flags & SECTION_FLAG_IS_WRAPPER) { |
1522 |
1 |
printf("{\n"); |
|
1523 |
1 |
json->indent_level++; |
|
1524 |
} else { |
||
1525 |
41 |
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
1526 |
41 |
json_escape_str(&buf, section->name, wctx); |
|
1527 |
41 |
JSON_INDENT(); |
|
1528 |
|||
1529 |
41 |
json->indent_level++; |
|
1530 |
✓✓ | 41 |
if (section->flags & SECTION_FLAG_IS_ARRAY) { |
1531 |
2 |
printf("\"%s\": [\n", buf.str); |
|
1532 |
✓✗✓✓ |
39 |
} else if (parent_section && !(parent_section->flags & SECTION_FLAG_IS_ARRAY)) { |
1533 |
8 |
printf("\"%s\": {%s", buf.str, json->item_start_end); |
|
1534 |
} else { |
||
1535 |
31 |
printf("{%s", json->item_start_end); |
|
1536 |
|||
1537 |
/* this is required so the parser can distinguish between packets and frames */ |
||
1538 |
✓✗✓✓ |
31 |
if (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES) { |
1539 |
✓✗ | 28 |
if (!json->compact) |
1540 |
28 |
JSON_INDENT(); |
|
1541 |
28 |
printf("\"type\": \"%s\"", section->name); |
|
1542 |
} |
||
1543 |
} |
||
1544 |
41 |
av_bprint_finalize(&buf, NULL); |
|
1545 |
} |
||
1546 |
42 |
} |
|
1547 |
|||
1548 |
42 |
static void json_print_section_footer(WriterContext *wctx) |
|
1549 |
{ |
||
1550 |
42 |
JSONContext *json = wctx->priv; |
|
1551 |
42 |
const struct section *section = wctx->section[wctx->level]; |
|
1552 |
|||
1553 |
✓✓ | 42 |
if (wctx->level == 0) { |
1554 |
1 |
json->indent_level--; |
|
1555 |
1 |
printf("\n}\n"); |
|
1556 |
✓✓ | 41 |
} else if (section->flags & SECTION_FLAG_IS_ARRAY) { |
1557 |
2 |
printf("\n"); |
|
1558 |
2 |
json->indent_level--; |
|
1559 |
2 |
JSON_INDENT(); |
|
1560 |
2 |
printf("]"); |
|
1561 |
} else { |
||
1562 |
39 |
printf("%s", json->item_start_end); |
|
1563 |
39 |
json->indent_level--; |
|
1564 |
✓✗ | 39 |
if (!json->compact) |
1565 |
39 |
JSON_INDENT(); |
|
1566 |
39 |
printf("}"); |
|
1567 |
} |
||
1568 |
42 |
} |
|
1569 |
|||
1570 |
283 |
static inline void json_print_item_str(WriterContext *wctx, |
|
1571 |
const char *key, const char *value) |
||
1572 |
{ |
||
1573 |
AVBPrint buf; |
||
1574 |
|||
1575 |
283 |
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
1576 |
283 |
printf("\"%s\":", json_escape_str(&buf, key, wctx)); |
|
1577 |
283 |
av_bprint_clear(&buf); |
|
1578 |
283 |
printf(" \"%s\"", json_escape_str(&buf, value, wctx)); |
|
1579 |
283 |
av_bprint_finalize(&buf, NULL); |
|
1580 |
283 |
} |
|
1581 |
|||
1582 |
283 |
static void json_print_str(WriterContext *wctx, const char *key, const char *value) |
|
1583 |
{ |
||
1584 |
283 |
JSONContext *json = wctx->priv; |
|
1585 |
566 |
const struct section *parent_section = wctx->level ? |
|
1586 |
✓✗ | 283 |
wctx->section[wctx->level-1] : NULL; |
1587 |
|||
1588 |
✓✓✓✗ ✓✓ |
283 |
if (wctx->nb_item[wctx->level] || (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES)) |
1589 |
278 |
printf("%s", json->item_sep); |
|
1590 |
✓✗ | 283 |
if (!json->compact) |
1591 |
283 |
JSON_INDENT(); |
|
1592 |
283 |
json_print_item_str(wctx, key, value); |
|
1593 |
283 |
} |
|
1594 |
|||
1595 |
271 |
static void json_print_int(WriterContext *wctx, const char *key, long long int value) |
|
1596 |
{ |
||
1597 |
271 |
JSONContext *json = wctx->priv; |
|
1598 |
542 |
const struct section *parent_section = wctx->level ? |
|
1599 |
✓✗ | 271 |
wctx->section[wctx->level-1] : NULL; |
1600 |
AVBPrint buf; |
||
1601 |
|||
1602 |
✓✓✓✗ ✗✓ |
271 |
if (wctx->nb_item[wctx->level] || (parent_section && parent_section->id == SECTION_ID_PACKETS_AND_FRAMES)) |
1603 |
265 |
printf("%s", json->item_sep); |
|
1604 |
✓✗ | 271 |
if (!json->compact) |
1605 |
271 |
JSON_INDENT(); |
|
1606 |
|||
1607 |
271 |
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
1608 |
271 |
printf("\"%s\": %lld", json_escape_str(&buf, key, wctx), value); |
|
1609 |
271 |
av_bprint_finalize(&buf, NULL); |
|
1610 |
271 |
} |
|
1611 |
|||
1612 |
static const Writer json_writer = { |
||
1613 |
.name = "json", |
||
1614 |
.priv_size = sizeof(JSONContext), |
||
1615 |
.init = json_init, |
||
1616 |
.print_section_header = json_print_section_header, |
||
1617 |
.print_section_footer = json_print_section_footer, |
||
1618 |
.print_integer = json_print_int, |
||
1619 |
.print_string = json_print_str, |
||
1620 |
.flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER, |
||
1621 |
.priv_class = &json_class, |
||
1622 |
}; |
||
1623 |
|||
1624 |
/* XML output */ |
||
1625 |
|||
1626 |
typedef struct XMLContext { |
||
1627 |
const AVClass *class; |
||
1628 |
int within_tag; |
||
1629 |
int indent_level; |
||
1630 |
int fully_qualified; |
||
1631 |
int xsd_strict; |
||
1632 |
} XMLContext; |
||
1633 |
|||
1634 |
#undef OFFSET |
||
1635 |
#define OFFSET(x) offsetof(XMLContext, x) |
||
1636 |
|||
1637 |
static const AVOption xml_options[] = { |
||
1638 |
{"fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, |
||
1639 |
{"q", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, |
||
1640 |
{"xsd_strict", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, |
||
1641 |
{"x", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 }, |
||
1642 |
{NULL}, |
||
1643 |
}; |
||
1644 |
|||
1645 |
DEFINE_WRITER_CLASS(xml); |
||
1646 |
|||
1647 |
1 |
static av_cold int xml_init(WriterContext *wctx) |
|
1648 |
{ |
||
1649 |
1 |
XMLContext *xml = wctx->priv; |
|
1650 |
|||
1651 |
✗✓ | 1 |
if (xml->xsd_strict) { |
1652 |
xml->fully_qualified = 1; |
||
1653 |
#define CHECK_COMPLIANCE(opt, opt_name) \ |
||
1654 |
if (opt) { \ |
||
1655 |
av_log(wctx, AV_LOG_ERROR, \ |
||
1656 |
"XSD-compliant output selected but option '%s' was selected, XML output may be non-compliant.\n" \ |
||
1657 |
"You need to disable such option with '-no%s'\n", opt_name, opt_name); \ |
||
1658 |
return AVERROR(EINVAL); \ |
||
1659 |
} |
||
1660 |
CHECK_COMPLIANCE(show_private_data, "private"); |
||
1661 |
CHECK_COMPLIANCE(show_value_unit, "unit"); |
||
1662 |
CHECK_COMPLIANCE(use_value_prefix, "prefix"); |
||
1663 |
|||
1664 |
if (do_show_frames && do_show_packets) { |
||
1665 |
av_log(wctx, AV_LOG_ERROR, |
||
1666 |
"Interleaved frames and packets are not allowed in XSD. " |
||
1667 |
"Select only one between the -show_frames and the -show_packets options.\n"); |
||
1668 |
return AVERROR(EINVAL); |
||
1669 |
} |
||
1670 |
} |
||
1671 |
|||
1672 |
1 |
return 0; |
|
1673 |
} |
||
1674 |
|||
1675 |
292 |
static const char *xml_escape_str(AVBPrint *dst, const char *src, void *log_ctx) |
|
1676 |
{ |
||
1677 |
const char *p; |
||
1678 |
|||
1679 |
✓✓ | 2143 |
for (p = src; *p; p++) { |
1680 |
✓✓✓✓ ✓✓ |
1851 |
switch (*p) { |
1681 |
1 |
case '&' : av_bprintf(dst, "%s", "&"); break; |
|
1682 |
1 |
case '<' : av_bprintf(dst, "%s", "<"); break; |
|
1683 |
1 |
case '>' : av_bprintf(dst, "%s", ">"); break; |
|
1684 |
2 |
case '"' : av_bprintf(dst, "%s", """); break; |
|
1685 |
2 |
case '\'': av_bprintf(dst, "%s", "'"); break; |
|
1686 |
1844 |
default: av_bprint_chars(dst, *p, 1); |
|
1687 |
} |
||
1688 |
} |
||
1689 |
|||
1690 |
292 |
return dst->str; |
|
1691 |
} |
||
1692 |
|||
1693 |
#define XML_INDENT() printf("%*c", xml->indent_level * 4, ' ') |
||
1694 |
|||
1695 |
42 |
static void xml_print_section_header(WriterContext *wctx) |
|
1696 |
{ |
||
1697 |
42 |
XMLContext *xml = wctx->priv; |
|
1698 |
42 |
const struct section *section = wctx->section[wctx->level]; |
|
1699 |
84 |
const struct section *parent_section = wctx->level ? |
|
1700 |
✓✓ | 42 |
wctx->section[wctx->level-1] : NULL; |
1701 |
|||
1702 |
✓✓ | 42 |
if (wctx->level == 0) { |
1703 |
1 |
const char *qual = " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' " |
|
1704 |
"xmlns:ffprobe='http://www.ffmpeg.org/schema/ffprobe' " |
||
1705 |
"xsi:schemaLocation='http://www.ffmpeg.org/schema/ffprobe ffprobe.xsd'"; |
||
1706 |
|||
1707 |
1 |
printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); |
|
1708 |
2 |
printf("<%sffprobe%s>\n", |
|
1709 |
✗✓ | 1 |
xml->fully_qualified ? "ffprobe:" : "", |
1710 |
✗✓ | 1 |
xml->fully_qualified ? qual : ""); |
1711 |
1 |
return; |
|
1712 |
} |
||
1713 |
|||
1714 |
✓✓ | 41 |
if (xml->within_tag) { |
1715 |
4 |
xml->within_tag = 0; |
|
1716 |
4 |
printf(">\n"); |
|
1717 |
} |
||
1718 |
✓✓ | 41 |
if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) { |
1719 |
4 |
xml->indent_level++; |
|
1720 |
} else { |
||
1721 |
✓✗✓✓ |
37 |
if (parent_section && (parent_section->flags & SECTION_FLAG_IS_WRAPPER) && |
1722 |
✓✗✓✓ |
3 |
wctx->level && wctx->nb_item[wctx->level-1]) |
1723 |
2 |
printf("\n"); |
|
1724 |
37 |
xml->indent_level++; |
|
1725 |
|||
1726 |
✓✓ | 37 |
if (section->flags & SECTION_FLAG_IS_ARRAY) { |
1727 |
2 |
XML_INDENT(); printf("<%s>\n", section->name); |
|
1728 |
} else { |
||
1729 |
35 |
XML_INDENT(); printf("<%s ", section->name); |
|
1730 |
35 |
xml->within_tag = 1; |
|
1731 |
} |
||
1732 |
} |
||
1733 |
} |
||
1734 |
|||
1735 |
42 |
static void xml_print_section_footer(WriterContext *wctx) |
|
1736 |
{ |
||
1737 |
42 |
XMLContext *xml = wctx->priv; |
|
1738 |
42 |
const struct section *section = wctx->section[wctx->level]; |
|
1739 |
|||
1740 |
✓✓ | 42 |
if (wctx->level == 0) { |
1741 |
✗✓ | 1 |
printf("</%sffprobe>\n", xml->fully_qualified ? "ffprobe:" : ""); |
1742 |
✓✓ | 41 |
} else if (xml->within_tag) { |
1743 |
31 |
xml->within_tag = 0; |
|
1744 |
31 |
printf("/>\n"); |
|
1745 |
31 |
xml->indent_level--; |
|
1746 |
✓✓ | 10 |
} else if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) { |
1747 |
4 |
xml->indent_level--; |
|
1748 |
} else { |
||
1749 |
6 |
XML_INDENT(); printf("</%s>\n", section->name); |
|
1750 |
6 |
xml->indent_level--; |
|
1751 |
} |
||
1752 |
42 |
} |
|
1753 |
|||
1754 |
283 |
static void xml_print_str(WriterContext *wctx, const char *key, const char *value) |
|
1755 |
{ |
||
1756 |
AVBPrint buf; |
||
1757 |
283 |
XMLContext *xml = wctx->priv; |
|
1758 |
283 |
const struct section *section = wctx->section[wctx->level]; |
|
1759 |
|||
1760 |
283 |
av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
1761 |
|||
1762 |
✓✓ | 283 |
if (section->flags & SECTION_FLAG_HAS_VARIABLE_FIELDS) { |
1763 |
9 |
XML_INDENT(); |
|
1764 |
9 |
printf("<%s key=\"%s\"", |
|
1765 |
section->element_name, xml_escape_str(&buf, key, wctx)); |
||
1766 |
9 |
av_bprint_clear(&buf); |
|
1767 |
9 |
printf(" value=\"%s\"/>\n", xml_escape_str(&buf, value, wctx)); |
|
1768 |
} else { |
||
1769 |
✓✓ | 274 |
if (wctx->nb_item[wctx->level]) |
1770 |
245 |
printf(" "); |
|
1771 |
274 |
printf("%s=\"%s\"", key, xml_escape_str(&buf, value, wctx)); |
|
1772 |
} |
||
1773 |
|||
1774 |
283 |
av_bprint_finalize(&buf, NULL); |
|
1775 |
283 |
} |
|
1776 |
|||
1777 |
271 |
static void xml_print_int(WriterContext *wctx, const char *key, long long int value) |
|
1778 |
{ |
||
1779 |
✓✓ | 271 |
if (wctx->nb_item[wctx->level]) |
1780 |
265 |
printf(" "); |
|
1781 |
271 |
printf("%s=\"%lld\"", key, value); |
|
1782 |
271 |
} |
|
1783 |
|||
1784 |
static Writer xml_writer = { |
||
1785 |
.name = "xml", |
||
1786 |
.priv_size = sizeof(XMLContext), |
||
1787 |
.init = xml_init, |
||
1788 |
.print_section_header = xml_print_section_header, |
||
1789 |
.print_section_footer = xml_print_section_footer, |
||
1790 |
.print_integer = xml_print_int, |
||
1791 |
.print_string = xml_print_str, |
||
1792 |
.flags = WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER, |
||
1793 |
.priv_class = &xml_class, |
||
1794 |
}; |
||
1795 |
|||
1796 |
76 |
static void writer_register_all(void) |
|
1797 |
{ |
||
1798 |
static int initialized; |
||
1799 |
|||
1800 |
✗✓ | 76 |
if (initialized) |
1801 |
return; |
||
1802 |
76 |
initialized = 1; |
|
1803 |
|||
1804 |
76 |
writer_register(&default_writer); |
|
1805 |
76 |
writer_register(&compact_writer); |
|
1806 |
76 |
writer_register(&csv_writer); |
|
1807 |
76 |
writer_register(&flat_writer); |
|
1808 |
76 |
writer_register(&ini_writer); |
|
1809 |
76 |
writer_register(&json_writer); |
|
1810 |
76 |
writer_register(&xml_writer); |
|
1811 |
} |
||
1812 |
|||
1813 |
#define print_fmt(k, f, ...) do { \ |
||
1814 |
av_bprint_clear(&pbuf); \ |
||
1815 |
av_bprintf(&pbuf, f, __VA_ARGS__); \ |
||
1816 |
writer_print_string(w, k, pbuf.str, 0); \ |
||
1817 |
} while (0) |
||
1818 |
|||
1819 |
#define print_int(k, v) writer_print_integer(w, k, v) |
||
1820 |
#define print_q(k, v, s) writer_print_rational(w, k, v, s) |
||
1821 |
#define print_str(k, v) writer_print_string(w, k, v, 0) |
||
1822 |
#define print_str_opt(k, v) writer_print_string(w, k, v, PRINT_STRING_OPT) |
||
1823 |
#define print_str_validate(k, v) writer_print_string(w, k, v, PRINT_STRING_VALIDATE) |
||
1824 |
#define print_time(k, v, tb) writer_print_time(w, k, v, tb, 0) |
||
1825 |
#define print_ts(k, v) writer_print_ts(w, k, v, 0) |
||
1826 |
#define print_duration_time(k, v, tb) writer_print_time(w, k, v, tb, 1) |
||
1827 |
#define print_duration_ts(k, v) writer_print_ts(w, k, v, 1) |
||
1828 |
#define print_val(k, v, u) do { \ |
||
1829 |
struct unit_value uv; \ |
||
1830 |
uv.val.i = v; \ |
||
1831 |
uv.unit = u; \ |
||
1832 |
writer_print_string(w, k, value_string(val_str, sizeof(val_str), uv), 0); \ |
||
1833 |
} while (0) |
||
1834 |
|||
1835 |
#define print_section_header(s) writer_print_section_header(w, s) |
||
1836 |
#define print_section_footer(s) writer_print_section_footer(w, s) |
||
1837 |
|||
1838 |
#define REALLOCZ_ARRAY_STREAM(ptr, cur_n, new_n) \ |
||
1839 |
{ \ |
||
1840 |
ret = av_reallocp_array(&(ptr), (new_n), sizeof(*(ptr))); \ |
||
1841 |
if (ret < 0) \ |
||
1842 |
goto end; \ |
||
1843 |
memset( (ptr) + (cur_n), 0, ((new_n) - (cur_n)) * sizeof(*(ptr)) ); \ |
||
1844 |
} |
||
1845 |
|||
1846 |
1245 |
static inline int show_tags(WriterContext *w, AVDictionary *tags, int section_id) |
|
1847 |
{ |
||
1848 |
1245 |
AVDictionaryEntry *tag = NULL; |
|
1849 |
1245 |
int ret = 0; |
|
1850 |
|||
1851 |
✓✓ | 1245 |
if (!tags) |
1852 |
635 |
return 0; |
|
1853 |
610 |
writer_print_section_header(w, section_id); |
|
1854 |
|||
1855 |
✓✓ | 3101 |
while ((tag = av_dict_get(tags, "", tag, AV_DICT_IGNORE_SUFFIX))) { |
1856 |
✗✓ | 2491 |
if ((ret = print_str_validate(tag->key, tag->value)) < 0) |
1857 |
break; |
||
1858 |
} |
||
1859 |
610 |
writer_print_section_footer(w); |
|
1860 |
|||
1861 |
610 |
return ret; |
|
1862 |
} |
||
1863 |
|||
1864 |
1 |
static void print_dynamic_hdr10_plus(WriterContext *w, const AVDynamicHDRPlus *metadata) |
|
1865 |
{ |
||
1866 |
✗✓ | 1 |
if (!metadata) |
1867 |
return; |
||
1868 |
1 |
print_int("application version", metadata->application_version); |
|
1869 |
1 |
print_int("num_windows", metadata->num_windows); |
|
1870 |
✗✓ | 1 |
for (int n = 1; n < metadata->num_windows; n++) { |
1871 |
const AVHDRPlusColorTransformParams *params = &metadata->params[n]; |
||
1872 |
print_q("window_upper_left_corner_x", |
||
1873 |
params->window_upper_left_corner_x,'/'); |
||
1874 |
print_q("window_upper_left_corner_y", |
||
1875 |
params->window_upper_left_corner_y,'/'); |
||
1876 |
print_q("window_lower_right_corner_x", |
||
1877 |
params->window_lower_right_corner_x,'/'); |
||
1878 |
print_q("window_lower_right_corner_y", |
||
1879 |
params->window_lower_right_corner_y,'/'); |
||
1880 |
print_q("window_upper_left_corner_x", |
||
1881 |
params->window_upper_left_corner_x,'/'); |
||
1882 |
print_q("window_upper_left_corner_y", |
||
1883 |
params->window_upper_left_corner_y,'/'); |
||
1884 |
print_int("center_of_ellipse_x", |
||
1885 |
params->center_of_ellipse_x ) ; |
||
1886 |
print_int("center_of_ellipse_y", |
||
1887 |
params->center_of_ellipse_y ); |
||
1888 |
print_int("rotation_angle", |
||
1889 |
params->rotation_angle); |
||
1890 |
print_int("semimajor_axis_internal_ellipse", |
||
1891 |
params->semimajor_axis_internal_ellipse); |
||
1892 |
print_int("semimajor_axis_external_ellipse", |
||
1893 |
params->semimajor_axis_external_ellipse); |
||
1894 |
print_int("semiminor_axis_external_ellipse", |
||
1895 |
params->semiminor_axis_external_ellipse); |
||
1896 |
print_int("overlap_process_option", |
||
1897 |
params->overlap_process_option); |
||
1898 |
} |
||
1899 |
1 |
print_q("targeted_system_display_maximum_luminance", |
|
1900 |
metadata->targeted_system_display_maximum_luminance,'/'); |
||
1901 |
✗✓ | 1 |
if (metadata->targeted_system_display_actual_peak_luminance_flag) { |
1902 |
print_int("num_rows_targeted_system_display_actual_peak_luminance", |
||
1903 |
metadata->num_rows_targeted_system_display_actual_peak_luminance); |
||
1904 |
print_int("num_cols_targeted_system_display_actual_peak_luminance", |
||
1905 |
metadata->num_cols_targeted_system_display_actual_peak_luminance); |
||
1906 |
for (int i = 0; i < metadata->num_rows_targeted_system_display_actual_peak_luminance; i++) { |
||
1907 |
for (int j = 0; j < metadata->num_cols_targeted_system_display_actual_peak_luminance; j++) { |
||
1908 |
print_q("targeted_system_display_actual_peak_luminance", |
||
1909 |
metadata->targeted_system_display_actual_peak_luminance[i][j],'/'); |
||
1910 |
} |
||
1911 |
} |
||
1912 |
} |
||
1913 |
✓✓ | 2 |
for (int n = 0; n < metadata->num_windows; n++) { |
1914 |
1 |
const AVHDRPlusColorTransformParams *params = &metadata->params[n]; |
|
1915 |
✓✓ | 4 |
for (int i = 0; i < 3; i++) { |
1916 |
3 |
print_q("maxscl",params->maxscl[i],'/'); |
|
1917 |
} |
||
1918 |
1 |
print_q("average_maxrgb", |
|
1919 |
params->average_maxrgb,'/'); |
||
1920 |
1 |
print_int("num_distribution_maxrgb_percentiles", |
|
1921 |
params->num_distribution_maxrgb_percentiles); |
||
1922 |
✓✓ | 10 |
for (int i = 0; i < params->num_distribution_maxrgb_percentiles; i++) { |
1923 |
9 |
print_int("distribution_maxrgb_percentage", |
|
1924 |
params->distribution_maxrgb[i].percentage); |
||
1925 |
9 |
print_q("distribution_maxrgb_percentile", |
|
1926 |
params->distribution_maxrgb[i].percentile,'/'); |
||
1927 |
} |
||
1928 |
1 |
print_q("fraction_bright_pixels", |
|
1929 |
params->fraction_bright_pixels,'/'); |
||
1930 |
} |
||
1931 |
✗✓ | 1 |
if (metadata->mastering_display_actual_peak_luminance_flag) { |
1932 |
print_int("num_rows_mastering_display_actual_peak_luminance", |
||
1933 |
metadata->num_rows_mastering_display_actual_peak_luminance); |
||
1934 |
print_int("num_cols_mastering_display_actual_peak_luminance", |
||
1935 |
metadata->num_cols_mastering_display_actual_peak_luminance); |
||
1936 |
for (int i = 0; i < metadata->num_rows_mastering_display_actual_peak_luminance; i++) { |
||
1937 |
for (int j = 0; j < metadata->num_cols_mastering_display_actual_peak_luminance; j++) { |
||
1938 |
print_q("mastering_display_actual_peak_luminance", |
||
1939 |
metadata->mastering_display_actual_peak_luminance[i][j],'/'); |
||
1940 |
} |
||
1941 |
} |
||
1942 |
} |
||
1943 |
|||
1944 |
✓✓ | 2 |
for (int n = 0; n < metadata->num_windows; n++) { |
1945 |
1 |
const AVHDRPlusColorTransformParams *params = &metadata->params[n]; |
|
1946 |
✓✗ | 1 |
if (params->tone_mapping_flag) { |
1947 |
1 |
print_q("knee_point_x", params->knee_point_x,'/'); |
|
1948 |
1 |
print_q("knee_point_y", params->knee_point_y,'/'); |
|
1949 |
1 |
print_int("num_bezier_curve_anchors", |
|
1950 |
params->num_bezier_curve_anchors ); |
||
1951 |
✓✓ | 10 |
for (int i = 0; i < params->num_bezier_curve_anchors; i++) { |
1952 |
9 |
print_q("bezier_curve_anchors", |
|
1953 |
params->bezier_curve_anchors[i],'/'); |
||
1954 |
} |
||
1955 |
} |
||
1956 |
✗✓ | 1 |
if (params->color_saturation_mapping_flag) { |
1957 |
print_q("color_saturation_weight", |
||
1958 |
params->color_saturation_weight,'/'); |
||
1959 |
} |
||
1960 |
} |
||
1961 |
} |
||
1962 |
|||
1963 |
207 |
static void print_pkt_side_data(WriterContext *w, |
|
1964 |
AVCodecParameters *par, |
||
1965 |
const AVPacketSideData *side_data, |
||
1966 |
int nb_side_data, |
||
1967 |
SectionID id_data_list, |
||
1968 |
SectionID id_data) |
||
1969 |
{ |
||
1970 |
int i; |
||
1971 |
|||
1972 |
207 |
writer_print_section_header(w, id_data_list); |
|
1973 |
✓✓ | 417 |
for (i = 0; i < nb_side_data; i++) { |
1974 |
210 |
const AVPacketSideData *sd = &side_data[i]; |
|
1975 |
210 |
const char *name = av_packet_side_data_name(sd->type); |
|
1976 |
|||
1977 |
210 |
writer_print_section_header(w, id_data); |
|
1978 |
✓✗ | 210 |
print_str("side_data_type", name ? name : "unknown"); |
1979 |
✓✓✓✗ |
210 |
if (sd->type == AV_PKT_DATA_DISPLAYMATRIX && sd->size >= 9*4) { |
1980 |
2 |
writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1); |
|
1981 |
2 |
print_int("rotation", av_display_rotation_get((int32_t *)sd->data)); |
|
1982 |
✓✓ | 208 |
} else if (sd->type == AV_PKT_DATA_STEREO3D) { |
1983 |
2 |
const AVStereo3D *stereo = (AVStereo3D *)sd->data; |
|
1984 |
2 |
print_str("type", av_stereo3d_type_name(stereo->type)); |
|
1985 |
2 |
print_int("inverted", !!(stereo->flags & AV_STEREO3D_FLAG_INVERT)); |
|
1986 |
✓✓ | 206 |
} else if (sd->type == AV_PKT_DATA_SPHERICAL) { |
1987 |
2 |
const AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data; |
|
1988 |
2 |
print_str("projection", av_spherical_projection_name(spherical->projection)); |
|
1989 |
✗✓ | 2 |
if (spherical->projection == AV_SPHERICAL_CUBEMAP) { |
1990 |
print_int("padding", spherical->padding); |
||
1991 |
✓✗ | 2 |
} else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) { |
1992 |
size_t l, t, r, b; |
||
1993 |
2 |
av_spherical_tile_bounds(spherical, par->width, par->height, |
|
1994 |
&l, &t, &r, &b); |
||
1995 |
2 |
print_int("bound_left", l); |
|
1996 |
2 |
print_int("bound_top", t); |
|
1997 |
2 |
print_int("bound_right", r); |
|
1998 |
2 |
print_int("bound_bottom", b); |
|
1999 |
} |
||
2000 |
|||
2001 |
2 |
print_int("yaw", (double) spherical->yaw / (1 << 16)); |
|
2002 |
2 |
print_int("pitch", (double) spherical->pitch / (1 << 16)); |
|
2003 |
2 |
print_int("roll", (double) spherical->roll / (1 << 16)); |
|
2004 |
✓✓✓✗ |
204 |
} else if (sd->type == AV_PKT_DATA_SKIP_SAMPLES && sd->size == 10) { |
2005 |
5 |
print_int("skip_samples", AV_RL32(sd->data)); |
|
2006 |
5 |
print_int("discard_padding", AV_RL32(sd->data + 4)); |
|
2007 |
5 |
print_int("skip_reason", AV_RL8(sd->data + 8)); |
|
2008 |
5 |
print_int("discard_reason", AV_RL8(sd->data + 9)); |
|
2009 |
✓✓ | 199 |
} else if (sd->type == AV_PKT_DATA_MASTERING_DISPLAY_METADATA) { |
2010 |
1 |
AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data; |
|
2011 |
|||
2012 |
✓✗ | 1 |
if (metadata->has_primaries) { |
2013 |
1 |
print_q("red_x", metadata->display_primaries[0][0], '/'); |
|
2014 |
1 |
print_q("red_y", metadata->display_primaries[0][1], '/'); |
|
2015 |
1 |
print_q("green_x", metadata->display_primaries[1][0], '/'); |
|
2016 |
1 |
print_q("green_y", metadata->display_primaries[1][1], '/'); |
|
2017 |
1 |
print_q("blue_x", metadata->display_primaries[2][0], '/'); |
|
2018 |
1 |
print_q("blue_y", metadata->display_primaries[2][1], '/'); |
|
2019 |
|||
2020 |
1 |
print_q("white_point_x", metadata->white_point[0], '/'); |
|
2021 |
1 |
print_q("white_point_y", metadata->white_point[1], '/'); |
|
2022 |
} |
||
2023 |
|||
2024 |
✓✗ | 1 |
if (metadata->has_luminance) { |
2025 |
1 |
print_q("min_luminance", metadata->min_luminance, '/'); |
|
2026 |
1 |
print_q("max_luminance", metadata->max_luminance, '/'); |
|
2027 |
} |
||
2028 |
✓✓ | 198 |
} else if (sd->type == AV_PKT_DATA_CONTENT_LIGHT_LEVEL) { |
2029 |
1 |
AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data; |
|
2030 |
1 |
print_int("max_content", metadata->MaxCLL); |
|
2031 |
1 |
print_int("max_average", metadata->MaxFALL); |
|
2032 |
✗✓ | 197 |
} else if (sd->type == AV_PKT_DATA_DOVI_CONF) { |
2033 |
AVDOVIDecoderConfigurationRecord *dovi = (AVDOVIDecoderConfigurationRecord *)sd->data; |
||
2034 |
print_int("dv_version_major", dovi->dv_version_major); |
||
2035 |
print_int("dv_version_minor", dovi->dv_version_minor); |
||
2036 |
print_int("dv_profile", dovi->dv_profile); |
||
2037 |
print_int("dv_level", dovi->dv_level); |
||
2038 |
print_int("rpu_present_flag", dovi->rpu_present_flag); |
||
2039 |
print_int("el_present_flag", dovi->el_present_flag); |
||
2040 |
print_int("bl_present_flag", dovi->bl_present_flag); |
||
2041 |
print_int("dv_bl_signal_compatibility_id", dovi->dv_bl_signal_compatibility_id); |
||
2042 |
} |
||
2043 |
210 |
writer_print_section_footer(w); |
|
2044 |
} |
||
2045 |
207 |
writer_print_section_footer(w); |
|
2046 |
207 |
} |
|
2047 |
|||
2048 |
494 |
static void print_color_range(WriterContext *w, enum AVColorRange color_range) |
|
2049 |
{ |
||
2050 |
494 |
const char *val = av_color_range_name(color_range); |
|
2051 |
✓✗✓✓ |
494 |
if (!val || color_range == AVCOL_RANGE_UNSPECIFIED) { |
2052 |
401 |
print_str_opt("color_range", "unknown"); |
|
2053 |
} else { |
||
2054 |
93 |
print_str("color_range", val); |
|
2055 |
} |
||
2056 |
494 |
} |
|
2057 |
|||
2058 |
494 |
static void print_color_space(WriterContext *w, enum AVColorSpace color_space) |
|
2059 |
{ |
||
2060 |
494 |
const char *val = av_color_space_name(color_space); |
|
2061 |
✓✗✓✓ |
494 |
if (!val || color_space == AVCOL_SPC_UNSPECIFIED) { |
2062 |
416 |
print_str_opt("color_space", "unknown"); |
|
2063 |
} else { |
||
2064 |
78 |
print_str("color_space", val); |
|
2065 |
} |
||
2066 |
494 |
} |
|
2067 |
|||
2068 |
494 |
static void print_primaries(WriterContext *w, enum AVColorPrimaries color_primaries) |
|
2069 |
{ |
||
2070 |
494 |
const char *val = av_color_primaries_name(color_primaries); |
|
2071 |
✓✗✓✓ |
494 |
if (!val || color_primaries == AVCOL_PRI_UNSPECIFIED) { |
2072 |
419 |
print_str_opt("color_primaries", "unknown"); |
|
2073 |
} else { |
||
2074 |
75 |
print_str("color_primaries", val); |
|
2075 |
} |
||
2076 |
494 |
} |
|
2077 |
|||
2078 |
494 |
static void print_color_trc(WriterContext *w, enum AVColorTransferCharacteristic color_trc) |
|
2079 |
{ |
||
2080 |
494 |
const char *val = av_color_transfer_name(color_trc); |
|
2081 |
✓✗✓✓ |
494 |
if (!val || color_trc == AVCOL_TRC_UNSPECIFIED) { |
2082 |
418 |
print_str_opt("color_transfer", "unknown"); |
|
2083 |
} else { |
||
2084 |
76 |
print_str("color_transfer", val); |
|
2085 |
} |
||
2086 |
494 |
} |
|
2087 |
|||
2088 |
494 |
static void print_chroma_location(WriterContext *w, enum AVChromaLocation chroma_location) |
|
2089 |
{ |
||
2090 |
494 |
const char *val = av_chroma_location_name(chroma_location); |
|
2091 |
✓✗✓✓ |
494 |
if (!val || chroma_location == AVCHROMA_LOC_UNSPECIFIED) { |
2092 |
402 |
print_str_opt("chroma_location", "unspecified"); |
|
2093 |
} else { |
||
2094 |
92 |
print_str("chroma_location", val); |
|
2095 |
} |
||
2096 |
494 |
} |
|
2097 |
|||
2098 |
|||
2099 |
5952 |
static void clear_log(int need_lock) |
|
2100 |
{ |
||
2101 |
int i; |
||
2102 |
|||
2103 |
✓✗ | 5952 |
if (need_lock) |
2104 |
5952 |
pthread_mutex_lock(&log_mutex); |
|
2105 |
✗✓ | 5952 |
for (i=0; i<log_buffer_size; i++) { |
2106 |
av_freep(&log_buffer[i].context_name); |
||
2107 |
av_freep(&log_buffer[i].parent_name); |
||
2108 |
av_freep(&log_buffer[i].log_message); |
||
2109 |
} |
||
2110 |
5952 |
log_buffer_size = 0; |
|
2111 |
✓✗ | 5952 |
if(need_lock) |
2112 |
5952 |
pthread_mutex_unlock(&log_mutex); |
|
2113 |
5952 |
} |
|
2114 |
|||
2115 |
static int show_log(WriterContext *w, int section_ids, int section_id, int log_level) |
||
2116 |
{ |
||
2117 |
int i; |
||
2118 |
pthread_mutex_lock(&log_mutex); |
||
2119 |
if (!log_buffer_size) { |
||
2120 |
pthread_mutex_unlock(&log_mutex); |
||
2121 |
return 0; |
||
2122 |
} |
||
2123 |
writer_print_section_header(w, section_ids); |
||
2124 |
|||
2125 |
for (i=0; i<log_buffer_size; i++) { |
||
2126 |
if (log_buffer[i].log_level <= log_level) { |
||
2127 |
writer_print_section_header(w, section_id); |
||
2128 |
print_str("context", log_buffer[i].context_name); |
||
2129 |
print_int("level", log_buffer[i].log_level); |
||
2130 |
print_int("category", log_buffer[i].category); |
||
2131 |
if (log_buffer[i].parent_name) { |
||
2132 |
print_str("parent_context", log_buffer[i].parent_name); |
||
2133 |
print_int("parent_category", log_buffer[i].parent_category); |
||
2134 |
} else { |
||
2135 |
print_str_opt("parent_context", "N/A"); |
||
2136 |
print_str_opt("parent_category", "N/A"); |
||
2137 |
} |
||
2138 |
print_str("message", log_buffer[i].log_message); |
||
2139 |
writer_print_section_footer(w); |
||
2140 |
} |
||
2141 |
} |
||
2142 |
clear_log(0); |
||
2143 |
pthread_mutex_unlock(&log_mutex); |
||
2144 |
|||
2145 |
writer_print_section_footer(w); |
||
2146 |
|||
2147 |
return 0; |
||
2148 |
} |
||
2149 |
|||
2150 |
3588 |
static void show_packet(WriterContext *w, InputFile *ifile, AVPacket *pkt, int packet_idx) |
|
2151 |
{ |
||
2152 |
char val_str[128]; |
||
2153 |
3588 |
AVStream *st = ifile->streams[pkt->stream_index].st; |
|
2154 |
AVBPrint pbuf; |
||
2155 |
const char *s; |
||
2156 |
|||
2157 |
3588 |
av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
2158 |
|||
2159 |
3588 |
writer_print_section_header(w, SECTION_ID_PACKET); |
|
2160 |
|||
2161 |
3588 |
s = av_get_media_type_string(st->codecpar->codec_type); |
|
2162 |
✓✗ | 3588 |
if (s) print_str ("codec_type", s); |
2163 |
else print_str_opt("codec_type", "unknown"); |
||
2164 |
3588 |
print_int("stream_index", pkt->stream_index); |
|
2165 |
3588 |
print_ts ("pts", pkt->pts); |
|
2166 |
3588 |
print_time("pts_time", pkt->pts, &st->time_base); |
|
2167 |
3588 |
print_ts ("dts", pkt->dts); |
|
2168 |
3588 |
print_time("dts_time", pkt->dts, &st->time_base); |
|
2169 |
3588 |
print_duration_ts("duration", pkt->duration); |
|
2170 |
3588 |
print_duration_time("duration_time", pkt->duration, &st->time_base); |
|
2171 |
3588 |
print_duration_ts("convergence_duration", pkt->convergence_duration); |
|
2172 |
3588 |
print_duration_time("convergence_duration_time", pkt->convergence_duration, &st->time_base); |
|
2173 |
3588 |
print_val("size", pkt->size, unit_byte_str); |
|
2174 |
✓✓ | 3588 |
if (pkt->pos != -1) print_fmt ("pos", "%"PRId64, pkt->pos); |
2175 |
82 |
else print_str_opt("pos", "N/A"); |
|
2176 |
✓✓✓✓ |
3588 |
print_fmt("flags", "%c%c", pkt->flags & AV_PKT_FLAG_KEY ? 'K' : '_', |
2177 |
pkt->flags & AV_PKT_FLAG_DISCARD ? 'D' : '_'); |
||
2178 |
|||
2179 |
✓✓ | 3588 |
if (pkt->side_data_elems) { |
2180 |
int size; |
||
2181 |
const uint8_t *side_metadata; |
||
2182 |
|||
2183 |
200 |
side_metadata = av_packet_get_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA, &size); |
|
2184 |
✓✓✓✗ ✓✗ |
200 |
if (side_metadata && size && do_show_packet_tags) { |
2185 |
131 |
AVDictionary *dict = NULL; |
|
2186 |
✓✗ | 131 |
if (av_packet_unpack_dictionary(side_metadata, size, &dict) >= 0) |
2187 |
131 |
show_tags(w, dict, SECTION_ID_PACKET_TAGS); |
|
2188 |
131 |
av_dict_free(&dict); |
|
2189 |
} |
||
2190 |
|||
2191 |
200 |
print_pkt_side_data(w, st->codecpar, pkt->side_data, pkt->side_data_elems, |
|
2192 |
SECTION_ID_PACKET_SIDE_DATA_LIST, |
||
2193 |
SECTION_ID_PACKET_SIDE_DATA); |
||
2194 |
} |
||
2195 |
|||
2196 |
✗✓ | 3588 |
if (do_show_data) |
2197 |
writer_print_data(w, "data", pkt->data, pkt->size); |
||
2198 |
3588 |
writer_print_data_hash(w, "data_hash", pkt->data, pkt->size); |
|
2199 |
3588 |
writer_print_section_footer(w); |
|
2200 |
|||
2201 |
3588 |
av_bprint_finalize(&pbuf, NULL); |
|
2202 |
3588 |
fflush(stdout); |
|
2203 |
3588 |
} |
|
2204 |
|||
2205 |
static void show_subtitle(WriterContext *w, AVSubtitle *sub, AVStream *stream, |
||
2206 |
AVFormatContext *fmt_ctx) |
||
2207 |
{ |
||
2208 |
AVBPrint pbuf; |
||
2209 |
|||
2210 |
av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); |
||
2211 |
|||
2212 |
writer_print_section_header(w, SECTION_ID_SUBTITLE); |
||
2213 |
|||
2214 |
print_str ("media_type", "subtitle"); |
||
2215 |
print_ts ("pts", sub->pts); |
||
2216 |
print_time("pts_time", sub->pts, &AV_TIME_BASE_Q); |
||
2217 |
print_int ("format", sub->format); |
||
2218 |
print_int ("start_display_time", sub->start_display_time); |
||
2219 |
print_int ("end_display_time", sub->end_display_time); |
||
2220 |
print_int ("num_rects", sub->num_rects); |
||
2221 |
|||
2222 |
writer_print_section_footer(w); |
||
2223 |
|||
2224 |
av_bprint_finalize(&pbuf, NULL); |
||
2225 |
fflush(stdout); |
||
2226 |
} |
||
2227 |
|||
2228 |
3024 |
static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream, |
|
2229 |
AVFormatContext *fmt_ctx) |
||
2230 |
{ |
||
2231 |
AVBPrint pbuf; |
||
2232 |
char val_str[128]; |
||
2233 |
const char *s; |
||
2234 |
int i; |
||
2235 |
|||
2236 |
3024 |
av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
2237 |
|||
2238 |
3024 |
writer_print_section_header(w, SECTION_ID_FRAME); |
|
2239 |
|||
2240 |
3024 |
s = av_get_media_type_string(stream->codecpar->codec_type); |
|
2241 |
✓✗ | 3024 |
if (s) print_str ("media_type", s); |
2242 |
else print_str_opt("media_type", "unknown"); |
||
2243 |
3024 |
print_int("stream_index", stream->index); |
|
2244 |
3024 |
print_int("key_frame", frame->key_frame); |
|
2245 |
3024 |
print_ts ("pkt_pts", frame->pts); |
|
2246 |
3024 |
print_time("pkt_pts_time", frame->pts, &stream->time_base); |
|
2247 |
3024 |
print_ts ("pkt_dts", frame->pkt_dts); |
|
2248 |
3024 |
print_time("pkt_dts_time", frame->pkt_dts, &stream->time_base); |
|
2249 |
3024 |
print_ts ("best_effort_timestamp", frame->best_effort_timestamp); |
|
2250 |
3024 |
print_time("best_effort_timestamp_time", frame->best_effort_timestamp, &stream->time_base); |
|
2251 |
3024 |
print_duration_ts ("pkt_duration", frame->pkt_duration); |
|
2252 |
3024 |
print_duration_time("pkt_duration_time", frame->pkt_duration, &stream->time_base); |
|
2253 |
✓✓ | 3024 |
if (frame->pkt_pos != -1) print_fmt ("pkt_pos", "%"PRId64, frame->pkt_pos); |
2254 |
302 |
else print_str_opt("pkt_pos", "N/A"); |
|
2255 |
✓✗ | 3024 |
if (frame->pkt_size != -1) print_val ("pkt_size", frame->pkt_size, unit_byte_str); |
2256 |
else print_str_opt("pkt_size", "N/A"); |
||
2257 |
|||
2258 |
✓✓✗ | 3024 |
switch (stream->codecpar->codec_type) { |
2259 |
AVRational sar; |
||
2260 |
|||
2261 |
454 |
case AVMEDIA_TYPE_VIDEO: |
|
2262 |
454 |
print_int("width", frame->width); |
|
2263 |
454 |
print_int("height", frame->height); |
|
2264 |
454 |
s = av_get_pix_fmt_name(frame->format); |
|
2265 |
✓✗ | 454 |
if (s) print_str ("pix_fmt", s); |
2266 |
else print_str_opt("pix_fmt", "unknown"); |
||
2267 |
454 |
sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, frame); |
|
2268 |
✓✓ | 454 |
if (sar.num) { |
2269 |
451 |
print_q("sample_aspect_ratio", sar, ':'); |
|
2270 |
} else { |
||
2271 |
3 |
print_str_opt("sample_aspect_ratio", "N/A"); |
|
2272 |
} |
||
2273 |
454 |
print_fmt("pict_type", "%c", av_get_picture_type_char(frame->pict_type)); |
|
2274 |
454 |
print_int("coded_picture_number", frame->coded_picture_number); |
|
2275 |
454 |
print_int("display_picture_number", frame->display_picture_number); |
|
2276 |
454 |
print_int("interlaced_frame", frame->interlaced_frame); |
|
2277 |
454 |
print_int("top_field_first", frame->top_field_first); |
|
2278 |
454 |
print_int("repeat_pict", frame->repeat_pict); |
|
2279 |
|||
2280 |
454 |
print_color_range(w, frame->color_range); |
|
2281 |
454 |
print_color_space(w, frame->colorspace); |
|
2282 |
454 |
print_primaries(w, frame->color_primaries); |
|
2283 |
454 |
print_color_trc(w, frame->color_trc); |
|
2284 |
454 |
print_chroma_location(w, frame->chroma_location); |
|
2285 |
454 |
break; |
|
2286 |
|||
2287 |
2570 |
case AVMEDIA_TYPE_AUDIO: |
|
2288 |
2570 |
s = av_get_sample_fmt_name(frame->format); |
|
2289 |
✓✗ | 2570 |
if (s) print_str ("sample_fmt", s); |
2290 |
else print_str_opt("sample_fmt", "unknown"); |
||
2291 |
2570 |
print_int("nb_samples", frame->nb_samples); |
|
2292 |
2570 |
print_int("channels", frame->channels); |
|
2293 |
✓✓ | 2570 |
if (frame->channel_layout) { |
2294 |
2352 |
av_bprint_clear(&pbuf); |
|
2295 |
2352 |
av_bprint_channel_layout(&pbuf, frame->channels, |
|
2296 |
frame->channel_layout); |
||
2297 |
2352 |
print_str ("channel_layout", pbuf.str); |
|
2298 |
} else |
||
2299 |
218 |
print_str_opt("channel_layout", "unknown"); |
|
2300 |
2570 |
break; |
|
2301 |
} |
||
2302 |
✓✓ | 3024 |
if (do_show_frame_tags) |
2303 |
1043 |
show_tags(w, frame->metadata, SECTION_ID_FRAME_TAGS); |
|
2304 |
✗✓ | 3024 |
if (do_show_log) |
2305 |
show_log(w, SECTION_ID_FRAME_LOGS, SECTION_ID_FRAME_LOG, do_show_log); |
||
2306 |
✓✓ | 3024 |
if (frame->nb_side_data) { |
2307 |
70 |
writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_LIST); |
|
2308 |
✓✓ | 144 |
for (i = 0; i < frame->nb_side_data; i++) { |
2309 |
74 |
AVFrameSideData *sd = frame->side_data[i]; |
|
2310 |
const char *name; |
||
2311 |
|||
2312 |
74 |
writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA); |
|
2313 |
74 |
name = av_frame_side_data_name(sd->type); |
|
2314 |
✓✗ | 74 |
print_str("side_data_type", name ? name : "unknown"); |
2315 |
✗✓✗✗ |
74 |
if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) { |
2316 |
writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1); |
||
2317 |
print_int("rotation", av_display_rotation_get((int32_t *)sd->data)); |
||
2318 |
✗✓✗✗ |
74 |
} else if (sd->type == AV_FRAME_DATA_GOP_TIMECODE && sd->size >= 8) { |
2319 |
char tcbuf[AV_TIMECODE_STR_SIZE]; |
||
2320 |
av_timecode_make_mpeg_tc_string(tcbuf, *(int64_t *)(sd->data)); |
||
2321 |
print_str("timecode", tcbuf); |
||
2322 |
✓✓✓✗ |
75 |
} else if (sd->type == AV_FRAME_DATA_S12M_TIMECODE && sd->size == 16) { |
2323 |
1 |
uint32_t *tc = (uint32_t*)sd->data; |
|
2324 |
1 |
int m = FFMIN(tc[0],3); |
|
2325 |
1 |
writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST); |
|
2326 |
✓✓ | 2 |
for (int j = 1; j <= m ; j++) { |
2327 |
char tcbuf[AV_TIMECODE_STR_SIZE]; |
||
2328 |
1 |
av_timecode_make_smpte_tc_string2(tcbuf, stream->avg_frame_rate, tc[j], 0, 0); |
|
2329 |
1 |
writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_TIMECODE); |
|
2330 |
1 |
print_str("value", tcbuf); |
|
2331 |
1 |
writer_print_section_footer(w); |
|
2332 |
} |
||
2333 |
1 |
writer_print_section_footer(w); |
|
2334 |
✓✓ | 73 |
} else if (sd->type == AV_FRAME_DATA_MASTERING_DISPLAY_METADATA) { |
2335 |
1 |
AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data; |
|
2336 |
|||
2337 |
✓✗ | 1 |
if (metadata->has_primaries) { |
2338 |
1 |
print_q("red_x", metadata->display_primaries[0][0], '/'); |
|
2339 |
1 |
print_q("red_y", metadata->display_primaries[0][1], '/'); |
|
2340 |
1 |
print_q("green_x", metadata->display_primaries[1][0], '/'); |
|
2341 |
1 |
print_q("green_y", metadata->display_primaries[1][1], '/'); |
|
2342 |
1 |
print_q("blue_x", metadata->display_primaries[2][0], '/'); |
|
2343 |
1 |
print_q("blue_y", metadata->display_primaries[2][1], '/'); |
|
2344 |
|||
2345 |
1 |
print_q("white_point_x", metadata->white_point[0], '/'); |
|
2346 |
1 |
print_q("white_point_y", metadata->white_point[1], '/'); |
|
2347 |
} |
||
2348 |
|||
2349 |
✓✗ | 1 |
if (metadata->has_luminance) { |
2350 |
1 |
print_q("min_luminance", metadata->min_luminance, '/'); |
|
2351 |
1 |
print_q("max_luminance", metadata->max_luminance, '/'); |
|
2352 |
} |
||
2353 |
✓✓ | 72 |
} else if (sd->type == AV_FRAME_DATA_DYNAMIC_HDR_PLUS) { |
2354 |
1 |
AVDynamicHDRPlus *metadata = (AVDynamicHDRPlus *)sd->data; |
|
2355 |
1 |
print_dynamic_hdr10_plus(w, metadata); |
|
2356 |
✓✓ | 71 |
} else if (sd->type == AV_FRAME_DATA_CONTENT_LIGHT_LEVEL) { |
2357 |
1 |
AVContentLightMetadata *metadata = (AVContentLightMetadata *)sd->data; |
|
2358 |
1 |
print_int("max_content", metadata->MaxCLL); |
|
2359 |
1 |
print_int("max_average", metadata->MaxFALL); |
|
2360 |
✗✓ | 70 |
} else if (sd->type == AV_FRAME_DATA_ICC_PROFILE) { |
2361 |
AVDictionaryEntry *tag = av_dict_get(sd->metadata, "name", NULL, AV_DICT_MATCH_CASE); |
||
2362 |
if (tag) |
||
2363 |
print_str(tag->key, tag->value); |
||
2364 |
print_int("size", sd->size); |
||
2365 |
} |
||
2366 |
74 |
writer_print_section_footer(w); |
|
2367 |
} |
||
2368 |
70 |
writer_print_section_footer(w); |
|
2369 |
} |
||
2370 |
|||
2371 |
3024 |
writer_print_section_footer(w); |
|
2372 |
|||
2373 |
3024 |
av_bprint_finalize(&pbuf, NULL); |
|
2374 |
3024 |
fflush(stdout); |
|
2375 |
3024 |
} |
|
2376 |
|||
2377 |
5952 |
static av_always_inline int process_frame(WriterContext *w, |
|
2378 |
InputFile *ifile, |
||
2379 |
AVFrame *frame, AVPacket *pkt, |
||
2380 |
int *packet_new) |
||
2381 |
{ |
||
2382 |
5952 |
AVFormatContext *fmt_ctx = ifile->fmt_ctx; |
|
2383 |
5952 |
AVCodecContext *dec_ctx = ifile->streams[pkt->stream_index].dec_ctx; |
|
2384 |
5952 |
AVCodecParameters *par = ifile->streams[pkt->stream_index].st->codecpar; |
|
2385 |
AVSubtitle sub; |
||
2386 |
5952 |
int ret = 0, got_frame = 0; |
|
2387 |
|||
2388 |
5952 |
clear_log(1); |
|
2389 |
✓✗✓✗ |
5952 |
if (dec_ctx && dec_ctx->codec) { |
2390 |
✓✗✗ | 5952 |
switch (par->codec_type) { |
2391 |
5952 |
case AVMEDIA_TYPE_VIDEO: |
|
2392 |
case AVMEDIA_TYPE_AUDIO: |
||
2393 |
✓✓ | 5952 |
if (*packet_new) { |
2394 |
2934 |
ret = avcodec_send_packet(dec_ctx, pkt); |
|
2395 |
✗✓ | 2934 |
if (ret == AVERROR(EAGAIN)) { |
2396 |
ret = 0; |
||
2397 |
✓✓✓✓ |
2934 |
} else if (ret >= 0 || ret == AVERROR_EOF) { |
2398 |
2932 |
ret = 0; |
|
2399 |
2932 |
*packet_new = 0; |
|
2400 |
} |
||
2401 |
} |
||
2402 |
✓✓ | 5952 |
if (ret >= 0) { |
2403 |
5950 |
ret = avcodec_receive_frame(dec_ctx, frame); |
|
2404 |
✓✓ | 5950 |
if (ret >= 0) { |
2405 |
3024 |
got_frame = 1; |
|
2406 |
✓✓✓✗ |
2926 |
} else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { |
2407 |
2926 |
ret = 0; |
|
2408 |
} |
||
2409 |
} |
||
2410 |
5952 |
break; |
|
2411 |
|||
2412 |
case AVMEDIA_TYPE_SUBTITLE: |
||
2413 |
if (*packet_new) |
||
2414 |
ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_frame, pkt); |
||
2415 |
*packet_new = 0; |
||
2416 |
break; |
||
2417 |
default: |
||
2418 |
*packet_new = 0; |
||
2419 |
} |
||
2420 |
} else { |
||
2421 |
*packet_new = 0; |
||
2422 |
} |
||
2423 |
|||
2424 |
✓✓ | 5952 |
if (ret < 0) |
2425 |
2 |
return ret; |
|
2426 |
✓✓ | 5950 |
if (got_frame) { |
2427 |
3024 |
int is_sub = (par->codec_type == AVMEDIA_TYPE_SUBTITLE); |
|
2428 |
3024 |
nb_streams_frames[pkt->stream_index]++; |
|
2429 |
✓✗ | 3024 |
if (do_show_frames) |
2430 |
✗✓ | 3024 |
if (is_sub) |
2431 |
show_subtitle(w, &sub, ifile->streams[pkt->stream_index].st, fmt_ctx); |
||
2432 |
else |
||
2433 |
3024 |
show_frame(w, frame, ifile->streams[pkt->stream_index].st, fmt_ctx); |
|
2434 |
✗✓ | 3024 |
if (is_sub) |
2435 |
avsubtitle_free(&sub); |
||
2436 |
} |
||
2437 |
✓✓✗✓ |
5950 |
return got_frame || *packet_new; |
2438 |
} |
||
2439 |
|||
2440 |
47 |
static void log_read_interval(const ReadInterval *interval, void *log_ctx, int log_level) |
|
2441 |
{ |
||
2442 |
47 |
av_log(log_ctx, log_level, "id:%d", interval->id); |
|
2443 |
|||
2444 |
✗✓ | 47 |
if (interval->has_start) { |
2445 |
av_log(log_ctx, log_level, " start:%s%s", interval->start_is_offset ? "+" : "", |
||
2446 |
av_ts2timestr(interval->start, &AV_TIME_BASE_Q)); |
||
2447 |
} else { |
||
2448 |
47 |
av_log(log_ctx, log_level, " start:N/A"); |
|
2449 |
} |
||
2450 |
|||
2451 |
✗✓ | 47 |
if (interval->has_end) { |
2452 |
av_log(log_ctx, log_level, " end:%s", interval->end_is_offset ? "+" : ""); |
||
2453 |
if (interval->duration_frames) |
||
2454 |
av_log(log_ctx, log_level, "#%"PRId64, interval->end); |
||
2455 |
else |
||
2456 |
av_log(log_ctx, log_level, "%s", av_ts2timestr(interval->end, &AV_TIME_BASE_Q)); |
||
2457 |
} else { |
||
2458 |
47 |
av_log(log_ctx, log_level, " end:N/A"); |
|
2459 |
} |
||
2460 |
|||
2461 |
47 |
av_log(log_ctx, log_level, "\n"); |
|
2462 |
47 |
} |
|
2463 |
|||
2464 |
47 |
static int read_interval_packets(WriterContext *w, InputFile *ifile, |
|
2465 |
const ReadInterval *interval, int64_t *cur_ts) |
||
2466 |
{ |
||
2467 |
47 |
AVFormatContext *fmt_ctx = ifile->fmt_ctx; |
|
2468 |
AVPacket pkt; |
||
2469 |
47 |
AVFrame *frame = NULL; |
|
2470 |
47 |
int ret = 0, i = 0, frame_count = 0; |
|
2471 |
47 |
int64_t start = -INT64_MAX, end = interval->end; |
|
2472 |
✗✓✗✗ |
47 |
int has_start = 0, has_end = interval->has_end && !interval->end_is_offset; |
2473 |
|||
2474 |
47 |
av_init_packet(&pkt); |
|
2475 |
|||
2476 |
47 |
av_log(NULL, AV_LOG_VERBOSE, "Processing read interval "); |
|
2477 |
47 |
log_read_interval(interval, NULL, AV_LOG_VERBOSE); |
|
2478 |
|||
2479 |
✗✓ | 47 |
if (interval->has_start) { |
2480 |
int64_t target; |
||
2481 |
if (interval->start_is_offset) { |
||
2482 |
if (*cur_ts == AV_NOPTS_VALUE) { |
||
2483 |
av_log(NULL, AV_LOG_ERROR, |
||
2484 |
"Could not seek to relative position since current " |
||
2485 |
"timestamp is not defined\n"); |
||
2486 |
ret = AVERROR(EINVAL); |
||
2487 |
goto end; |
||
2488 |
} |
||
2489 |
target = *cur_ts + interval->start; |
||
2490 |
} else { |
||
2491 |
target = interval->start; |
||
2492 |
} |
||
2493 |
|||
2494 |
av_log(NULL, AV_LOG_VERBOSE, "Seeking to read interval start point %s\n", |
||
2495 |
av_ts2timestr(target, &AV_TIME_BASE_Q)); |
||
2496 |
if ((ret = avformat_seek_file(fmt_ctx, -1, -INT64_MAX, target, INT64_MAX, 0)) < 0) { |
||
2497 |
av_log(NULL, AV_LOG_ERROR, "Could not seek to position %"PRId64": %s\n", |
||
2498 |
interval->start, av_err2str(ret)); |
||
2499 |
goto end; |
||
2500 |
} |
||
2501 |
} |
||
2502 |
|||
2503 |
47 |
frame = av_frame_alloc(); |
|
2504 |
✗✓ | 47 |
if (!frame) { |
2505 |
ret = AVERROR(ENOMEM); |
||
2506 |
goto end; |
||
2507 |
} |
||
2508 |
✓✓ | 6335 |
while (!av_read_frame(fmt_ctx, &pkt)) { |
2509 |
✗✓ | 6288 |
if (fmt_ctx->nb_streams > nb_streams) { |
2510 |
REALLOCZ_ARRAY_STREAM(nb_streams_frames, nb_streams, fmt_ctx->nb_streams); |
||
2511 |
REALLOCZ_ARRAY_STREAM(nb_streams_packets, nb_streams, fmt_ctx->nb_streams); |
||
2512 |
REALLOCZ_ARRAY_STREAM(selected_streams, nb_streams, fmt_ctx->nb_streams); |
||
2513 |
nb_streams = fmt_ctx->nb_streams; |
||
2514 |
} |
||
2515 |
✓✓ | 6288 |
if (selected_streams[pkt.stream_index]) { |
2516 |
6285 |
AVRational tb = ifile->streams[pkt.stream_index].st->time_base; |
|
2517 |
|||
2518 |
✓✓ | 6285 |
if (pkt.pts != AV_NOPTS_VALUE) |
2519 |
6272 |
*cur_ts = av_rescale_q(pkt.pts, tb, AV_TIME_BASE_Q); |
|
2520 |
|||
2521 |
✓✓✓✓ |
6285 |
if (!has_start && *cur_ts != AV_NOPTS_VALUE) { |
2522 |
44 |
start = *cur_ts; |
|
2523 |
44 |
has_start = 1; |
|
2524 |
} |
||
2525 |
|||
2526 |
✓✓✓✗ ✗✓ |
6285 |
if (has_start && !has_end && interval->end_is_offset) { |
2527 |
end = start + interval->end; |
||
2528 |
has_end = 1; |
||
2529 |
} |
||
2530 |
|||
2531 |
✗✓✗✗ |
6285 |
if (interval->end_is_offset && interval->duration_frames) { |
2532 |
if (frame_count >= interval->end) |
||
2533 |
break; |
||
2534 |
✗✓✗✗ ✗✗ |
6285 |
} else if (has_end && *cur_ts != AV_NOPTS_VALUE && *cur_ts >= end) { |
2535 |
break; |
||
2536 |
} |
||
2537 |
|||
2538 |
6285 |
frame_count++; |
|
2539 |
✓✓ | 6285 |
if (do_read_packets) { |
2540 |
✓✗ | 3588 |
if (do_show_packets) |
2541 |
3588 |
show_packet(w, ifile, &pkt, i++); |
|
2542 |
3588 |
nb_streams_packets[pkt.stream_index]++; |
|
2543 |
} |
||
2544 |
✓✓ | 6285 |
if (do_read_frames) { |
2545 |
2878 |
int packet_new = 1; |
|
2546 |
✓✓ | 5896 |
while (process_frame(w, ifile, frame, &pkt, &packet_new) > 0); |
2547 |
} |
||
2548 |
} |
||
2549 |
6288 |
av_packet_unref(&pkt); |
|
2550 |
} |
||
2551 |
47 |
av_packet_unref(&pkt); |
|
2552 |
//Flush remaining frames that are cached in the decoder |
||
2553 |
✓✓ | 117 |
for (i = 0; i < fmt_ctx->nb_streams; i++) { |
2554 |
70 |
pkt.stream_index = i; |
|
2555 |
✓✓ | 70 |
if (do_read_frames) |
2556 |
✓✓ | 56 |
while (process_frame(w, ifile, frame, &pkt, &(int){1}) > 0); |
2557 |
} |
||
2558 |
|||
2559 |
47 |
end: |
|
2560 |
47 |
av_frame_free(&frame); |
|
2561 |
✗✓ | 47 |
if (ret < 0) { |
2562 |
av_log(NULL, AV_LOG_ERROR, "Could not read packets in interval "); |
||
2563 |
log_read_interval(interval, NULL, AV_LOG_ERROR); |
||
2564 |
} |
||
2565 |
47 |
return ret; |
|
2566 |
} |
||
2567 |
|||
2568 |
47 |
static int read_packets(WriterContext *w, InputFile *ifile) |
|
2569 |
{ |
||
2570 |
47 |
AVFormatContext *fmt_ctx = ifile->fmt_ctx; |
|
2571 |
47 |
int i, ret = 0; |
|
2572 |
47 |
int64_t cur_ts = fmt_ctx->start_time; |
|
2573 |
|||
2574 |
✓✗ | 47 |
if (read_intervals_nb == 0) { |
2575 |
47 |
ReadInterval interval = (ReadInterval) { .has_start = 0, .has_end = 0 }; |
|
2576 |
47 |
ret = read_interval_packets(w, ifile, &interval, &cur_ts); |
|
2577 |
} else { |
||
2578 |
for (i = 0; i < read_intervals_nb; i++) { |
||
2579 |
ret = read_interval_packets(w, ifile, &read_intervals[i], &cur_ts); |
||
2580 |
if (ret < 0) |
||
2581 |
break; |
||
2582 |
} |
||
2583 |
} |
||
2584 |
|||
2585 |
47 |
return ret; |
|
2586 |
} |
||
2587 |
|||
2588 |
86 |
static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_idx, InputStream *ist, int in_program) |
|
2589 |
{ |
||
2590 |
86 |
AVStream *stream = ist->st; |
|
2591 |
AVCodecParameters *par; |
||
2592 |
AVCodecContext *dec_ctx; |
||
2593 |
char val_str[128]; |
||
2594 |
const char *s; |
||
2595 |
AVRational sar, dar; |
||
2596 |
AVBPrint pbuf; |
||
2597 |
const AVCodecDescriptor *cd; |
||
2598 |
86 |
int ret = 0; |
|
2599 |
86 |
const char *profile = NULL; |
|
2600 |
|||
2601 |
86 |
av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
2602 |
|||
2603 |
✓✓ | 86 |
writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM : SECTION_ID_STREAM); |
2604 |
|||
2605 |
86 |
print_int("index", stream->index); |
|
2606 |
|||
2607 |
86 |
par = stream->codecpar; |
|
2608 |
86 |
dec_ctx = ist->dec_ctx; |
|
2609 |
✓✓ | 86 |
if (cd = avcodec_descriptor_get(par->codec_id)) { |
2610 |
83 |
print_str("codec_name", cd->name); |
|
2611 |
✓✓ | 83 |
if (!do_bitexact) { |
2612 |
✓✗ | 9 |
print_str("codec_long_name", |
2613 |
cd->long_name ? cd->long_name : "unknown"); |
||
2614 |
} |
||
2615 |
} else { |
||
2616 |
3 |
print_str_opt("codec_name", "unknown"); |
|
2617 |
✗✓ | 3 |
if (!do_bitexact) { |
2618 |
print_str_opt("codec_long_name", "unknown"); |
||
2619 |
} |
||
2620 |
} |
||
2621 |
|||
2622 |
✓✓✓✓ |
86 |
if (!do_bitexact && (profile = avcodec_profile_name(par->codec_id, par->profile))) |
2623 |
7 |
print_str("profile", profile); |
|
2624 |
else { |
||
2625 |
✓✓ | 79 |
if (par->profile != FF_PROFILE_UNKNOWN) { |
2626 |
char profile_num[12]; |
||
2627 |
28 |
snprintf(profile_num, sizeof(profile_num), "%d", par->profile); |
|
2628 |
28 |
print_str("profile", profile_num); |
|
2629 |
} else |
||
2630 |
51 |
print_str_opt("profile", "unknown"); |
|
2631 |
} |
||
2632 |
|||
2633 |
86 |
s = av_get_media_type_string(par->codec_type); |
|
2634 |
✓✗ | 86 |
if (s) print_str ("codec_type", s); |
2635 |
else print_str_opt("codec_type", "unknown"); |
||
2636 |
#if FF_API_LAVF_AVCTX |
||
2637 |
✓✓ | 86 |
if (dec_ctx) |
2638 |
80 |
print_q("codec_time_base", dec_ctx->time_base, '/'); |
|
2639 |
#endif |
||
2640 |
|||
2641 |
/* print AVI/FourCC tag */ |
||
2642 |
86 |
print_str("codec_tag_string", av_fourcc2str(par->codec_tag)); |
|
2643 |
86 |
print_fmt("codec_tag", "0x%04"PRIx32, par->codec_tag); |
|
2644 |
|||
2645 |
✓✓✗✓ |
86 |
switch (par->codec_type) { |
2646 |
40 |
case AVMEDIA_TYPE_VIDEO: |
|
2647 |
40 |
print_int("width", par->width); |
|
2648 |
40 |
print_int("height", par->height); |
|
2649 |
#if FF_API_LAVF_AVCTX |
||
2650 |
✓✗ | 40 |
if (dec_ctx) { |
2651 |
40 |
print_int("coded_width", dec_ctx->coded_width); |
|
2652 |
40 |
print_int("coded_height", dec_ctx->coded_height); |
|
2653 |
40 |
print_int("closed_captions", !!(dec_ctx->properties & FF_CODEC_PROPERTY_CLOSED_CAPTIONS)); |
|
2654 |
} |
||
2655 |
#endif |
||
2656 |
40 |
print_int("has_b_frames", par->video_delay); |
|
2657 |
40 |
sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL); |
|
2658 |
✓✓ | 40 |
if (sar.num) { |
2659 |
35 |
print_q("sample_aspect_ratio", sar, ':'); |
|
2660 |
35 |
av_reduce(&dar.num, &dar.den, |
|
2661 |
35 |
par->width * sar.num, |
|
2662 |
35 |
par->height * sar.den, |
|
2663 |
1024*1024); |
||
2664 |
35 |
print_q("display_aspect_ratio", dar, ':'); |
|
2665 |
} else { |
||
2666 |
5 |
print_str_opt("sample_aspect_ratio", "N/A"); |
|
2667 |
5 |
print_str_opt("display_aspect_ratio", "N/A"); |
|
2668 |
} |
||
2669 |
40 |
s = av_get_pix_fmt_name(par->format); |
|
2670 |
✓✓ | 40 |
if (s) print_str ("pix_fmt", s); |
2671 |
2 |
else print_str_opt("pix_fmt", "unknown"); |
|
2672 |
40 |
print_int("level", par->level); |
|
2673 |
|||
2674 |
40 |
print_color_range(w, par->color_range); |
|
2675 |
40 |
print_color_space(w, par->color_space); |
|
2676 |
40 |
print_color_trc(w, par->color_trc); |
|
2677 |
40 |
print_primaries(w, par->color_primaries); |
|
2678 |
40 |
print_chroma_location(w, par->chroma_location); |
|
2679 |
|||
2680 |
✓✓ | 40 |
if (par->field_order == AV_FIELD_PROGRESSIVE) |
2681 |
6 |
print_str("field_order", "progressive"); |
|
2682 |
✓✓ | 34 |
else if (par->field_order == AV_FIELD_TT) |
2683 |
3 |
print_str("field_order", "tt"); |
|
2684 |
✓✓ | 31 |
else if (par->field_order == AV_FIELD_BB) |
2685 |
1 |
print_str("field_order", "bb"); |
|
2686 |
✓✓ | 30 |
else if (par->field_order == AV_FIELD_TB) |
2687 |
2 |
print_str("field_order", "tb"); |
|
2688 |
✗✓ | 28 |
else if (par->field_order == AV_FIELD_BT) |
2689 |
print_str("field_order", "bt"); |
||
2690 |
else |
||
2691 |
28 |
print_str_opt("field_order", "unknown"); |
|
2692 |
|||
2693 |
#if FF_API_PRIVATE_OPT |
||
2694 |
✓✗✗✓ |
40 |
if (dec_ctx && dec_ctx->timecode_frame_start >= 0) { |
2695 |
char tcbuf[AV_TIMECODE_STR_SIZE]; |
||
2696 |
av_timecode_make_mpeg_tc_string(tcbuf, dec_ctx->timecode_frame_start); |
||
2697 |
print_str("timecode", tcbuf); |
||
2698 |
} else { |
||
2699 |
40 |
print_str_opt("timecode", "N/A"); |
|
2700 |
} |
||
2701 |
#endif |
||
2702 |
✓✗ | 40 |
if (dec_ctx) |
2703 |
40 |
print_int("refs", dec_ctx->refs); |
|
2704 |
40 |
break; |
|
2705 |
|||
2706 |
40 |
case AVMEDIA_TYPE_AUDIO: |
|
2707 |
40 |
s = av_get_sample_fmt_name(par->format); |
|
2708 |
✓✗ | 40 |
if (s) print_str ("sample_fmt", s); |
2709 |
else print_str_opt("sample_fmt", "unknown"); |
||
2710 |
40 |
print_val("sample_rate", par->sample_rate, unit_hertz_str); |
|
2711 |
40 |
print_int("channels", par->channels); |
|
2712 |
|||
2713 |
✓✓ | 40 |
if (par->channel_layout) { |
2714 |
23 |
av_bprint_clear(&pbuf); |
|
2715 |
23 |
av_bprint_channel_layout(&pbuf, par->channels, par->channel_layout); |
|
2716 |
23 |
print_str ("channel_layout", pbuf.str); |
|
2717 |
} else { |
||
2718 |
17 |
print_str_opt("channel_layout", "unknown"); |
|
2719 |
} |
||
2720 |
|||
2721 |
40 |
print_int("bits_per_sample", av_get_bits_per_sample(par->codec_id)); |
|
2722 |
40 |
break; |
|
2723 |
|||
2724 |
case AVMEDIA_TYPE_SUBTITLE: |
||
2725 |
if (par->width) |
||
2726 |
print_int("width", par->width); |
||
2727 |
else |
||
2728 |
print_str_opt("width", "N/A"); |
||
2729 |
if (par->height) |
||
2730 |
print_int("height", par->height); |
||
2731 |
else |
||
2732 |
print_str_opt("height", "N/A"); |
||
2733 |
break; |
||
2734 |
} |
||
2735 |
|||
2736 |
✓✓✓✗ ✓✓✓✗ |
86 |
if (dec_ctx && dec_ctx->codec && dec_ctx->codec->priv_class && show_private_data) { |
2737 |
46 |
const AVOption *opt = NULL; |
|
2738 |
✓✓ | 225 |
while (opt = av_opt_next(dec_ctx->priv_data,opt)) { |
2739 |
uint8_t *str; |
||
2740 |
✓✓ | 179 |
if (opt->flags) continue; |
2741 |
✓✗ | 51 |
if (av_opt_get(dec_ctx->priv_data, opt->name, 0, &str) >= 0) { |
2742 |
51 |
print_str(opt->name, str); |
|
2743 |
51 |
av_free(str); |
|
2744 |
} |
||
2745 |
} |
||
2746 |
} |
||
2747 |
|||
2748 |
✓✓ | 86 |
if (fmt_ctx->iformat->flags & AVFMT_SHOW_IDS) print_fmt ("id", "0x%x", stream->id); |
2749 |
69 |
else print_str_opt("id", "N/A"); |
|
2750 |
86 |
print_q("r_frame_rate", stream->r_frame_rate, '/'); |
|
2751 |
86 |
print_q("avg_frame_rate", stream->avg_frame_rate, '/'); |
|
2752 |
86 |
print_q("time_base", stream->time_base, '/'); |
|
2753 |
86 |
print_ts ("start_pts", stream->start_time); |
|
2754 |
86 |
print_time("start_time", stream->start_time, &stream->time_base); |
|
2755 |
86 |
print_ts ("duration_ts", stream->duration); |
|
2756 |
86 |
print_time("duration", stream->duration, &stream->time_base); |
|
2757 |
✓✓ | 86 |
if (par->bit_rate > 0) print_val ("bit_rate", par->bit_rate, unit_bit_per_second_str); |
2758 |
37 |
else print_str_opt("bit_rate", "N/A"); |
|
2759 |
#if FF_API_LAVF_AVCTX |
||
2760 |
✓✓ | 86 |
if (stream->codec->rc_max_rate > 0) print_val ("max_bit_rate", stream->codec->rc_max_rate, unit_bit_per_second_str); |
2761 |
74 |
else print_str_opt("max_bit_rate", "N/A"); |
|
2762 |
#endif |
||
2763 |
✓✓✓✓ |
86 |
if (dec_ctx && dec_ctx->bits_per_raw_sample > 0) print_fmt("bits_per_raw_sample", "%d", dec_ctx->bits_per_raw_sample); |
2764 |
73 |
else print_str_opt("bits_per_raw_sample", "N/A"); |
|
2765 |
✓✓ | 86 |
if (stream->nb_frames) print_fmt ("nb_frames", "%"PRId64, stream->nb_frames); |
2766 |
63 |
else print_str_opt("nb_frames", "N/A"); |
|
2767 |
✓✓ | 86 |
if (nb_streams_frames[stream_idx]) print_fmt ("nb_read_frames", "%"PRIu64, nb_streams_frames[stream_idx]); |
2768 |
59 |
else print_str_opt("nb_read_frames", "N/A"); |
|
2769 |
✓✓ | 86 |
if (nb_streams_packets[stream_idx]) print_fmt ("nb_read_packets", "%"PRIu64, nb_streams_packets[stream_idx]); |
2770 |
48 |
else print_str_opt("nb_read_packets", "N/A"); |
|
2771 |
✗✓ | 86 |
if (do_show_data) |
2772 |
writer_print_data(w, "extradata", par->extradata, |
||
2773 |
par->extradata_size); |
||
2774 |
86 |
writer_print_data_hash(w, "extradata_hash", par->extradata, |
|
2775 |
par->extradata_size); |
||
2776 |
|||
2777 |
/* Print disposition information */ |
||
2778 |
#define PRINT_DISPOSITION(flagname, name) do { \ |
||
2779 |
print_int(name, !!(stream->disposition & AV_DISPOSITION_##flagname)); \ |
||
2780 |
} while (0) |
||
2781 |
|||
2782 |
✓✓ | 86 |
if (do_show_stream_disposition) { |
2783 |
✗✓ | 46 |
writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM_DISPOSITION : SECTION_ID_STREAM_DISPOSITION); |
2784 |
46 |
PRINT_DISPOSITION(DEFAULT, "default"); |
|
2785 |
46 |
PRINT_DISPOSITION(DUB, "dub"); |
|
2786 |
46 |
PRINT_DISPOSITION(ORIGINAL, "original"); |
|
2787 |
46 |
PRINT_DISPOSITION(COMMENT, "comment"); |
|
2788 |
46 |
PRINT_DISPOSITION(LYRICS, "lyrics"); |
|
2789 |
46 |
PRINT_DISPOSITION(KARAOKE, "karaoke"); |
|
2790 |
46 |
PRINT_DISPOSITION(FORCED, "forced"); |
|
2791 |
46 |
PRINT_DISPOSITION(HEARING_IMPAIRED, "hearing_impaired"); |
|
2792 |
46 |
PRINT_DISPOSITION(VISUAL_IMPAIRED, "visual_impaired"); |
|
2793 |
46 |
PRINT_DISPOSITION(CLEAN_EFFECTS, "clean_effects"); |
|
2794 |
46 |
PRINT_DISPOSITION(ATTACHED_PIC, "attached_pic"); |
|
2795 |
46 |
PRINT_DISPOSITION(TIMED_THUMBNAILS, "timed_thumbnails"); |
|
2796 |
46 |
writer_print_section_footer(w); |
|
2797 |
} |
||
2798 |
|||
2799 |
✓✓ | 86 |
if (do_show_stream_tags) |
2800 |
✗✓ | 46 |
ret = show_tags(w, stream->metadata, in_program ? SECTION_ID_PROGRAM_STREAM_TAGS : SECTION_ID_STREAM_TAGS); |
2801 |
|||
2802 |
✓✓ | 86 |
if (stream->nb_side_data) { |
2803 |
7 |
print_pkt_side_data(w, stream->codecpar, stream->side_data, stream->nb_side_data, |
|
2804 |
SECTION_ID_STREAM_SIDE_DATA_LIST, |
||
2805 |
SECTION_ID_STREAM_SIDE_DATA); |
||
2806 |
} |
||
2807 |
|||
2808 |
86 |
writer_print_section_footer(w); |
|
2809 |
86 |
av_bprint_finalize(&pbuf, NULL); |
|
2810 |
86 |
fflush(stdout); |
|
2811 |
|||
2812 |
86 |
return ret; |
|
2813 |
} |
||
2814 |
|||
2815 |
45 |
static int show_streams(WriterContext *w, InputFile *ifile) |
|
2816 |
{ |
||
2817 |
45 |
AVFormatContext *fmt_ctx = ifile->fmt_ctx; |
|
2818 |
45 |
int i, ret = 0; |
|
2819 |
|||
2820 |
45 |
writer_print_section_header(w, SECTION_ID_STREAMS); |
|
2821 |
✓✓ | 130 |
for (i = 0; i < ifile->nb_streams; i++) |
2822 |
✓✓ | 85 |
if (selected_streams[i]) { |
2823 |
78 |
ret = show_stream(w, fmt_ctx, i, &ifile->streams[i], 0); |
|
2824 |
✗✓ | 78 |
if (ret < 0) |
2825 |
break; |
||
2826 |
} |
||
2827 |
45 |
writer_print_section_footer(w); |
|
2828 |
|||
2829 |
45 |
return ret; |
|
2830 |
} |
||
2831 |
|||
2832 |
3 |
static int show_program(WriterContext *w, InputFile *ifile, AVProgram *program) |
|
2833 |
{ |
||
2834 |
3 |
AVFormatContext *fmt_ctx = ifile->fmt_ctx; |
|
2835 |
3 |
int i, ret = 0; |
|
2836 |
|||
2837 |
3 |
writer_print_section_header(w, SECTION_ID_PROGRAM); |
|
2838 |
3 |
print_int("program_id", program->id); |
|
2839 |
3 |
print_int("program_num", program->program_num); |
|
2840 |
3 |
print_int("nb_streams", program->nb_stream_indexes); |
|
2841 |
3 |
print_int("pmt_pid", program->pmt_pid); |
|
2842 |
3 |
print_int("pcr_pid", program->pcr_pid); |
|
2843 |
3 |
print_ts("start_pts", program->start_time); |
|
2844 |
3 |
print_time("start_time", program->start_time, &AV_TIME_BASE_Q); |
|
2845 |
3 |
print_ts("end_pts", program->end_time); |
|
2846 |
3 |
print_time("end_time", program->end_time, &AV_TIME_BASE_Q); |
|
2847 |
✗✓ | 3 |
if (do_show_program_tags) |
2848 |
ret = show_tags(w, program->metadata, SECTION_ID_PROGRAM_TAGS); |
||
2849 |
✗✓ | 3 |
if (ret < 0) |
2850 |
goto end; |
||
2851 |
|||
2852 |
3 |
writer_print_section_header(w, SECTION_ID_PROGRAM_STREAMS); |
|
2853 |
✓✓ | 12 |
for (i = 0; i < program->nb_stream_indexes; i++) { |
2854 |
✓✓ | 9 |
if (selected_streams[program->stream_index[i]]) { |
2855 |
8 |
ret = show_stream(w, fmt_ctx, program->stream_index[i], &ifile->streams[program->stream_index[i]], 1); |
|
2856 |
✗✓ | 8 |
if (ret < 0) |
2857 |
break; |
||
2858 |
} |
||
2859 |
} |
||
2860 |
3 |
writer_print_section_footer(w); |
|
2861 |
|||
2862 |
3 |
end: |
|
2863 |
3 |
writer_print_section_footer(w); |
|
2864 |
3 |
return ret; |
|
2865 |
} |
||
2866 |
|||
2867 |
28 |
static int show_programs(WriterContext *w, InputFile *ifile) |
|
2868 |
{ |
||
2869 |
28 |
AVFormatContext *fmt_ctx = ifile->fmt_ctx; |
|
2870 |
28 |
int i, ret = 0; |
|
2871 |
|||
2872 |
28 |
writer_print_section_header(w, SECTION_ID_PROGRAMS); |
|
2873 |
✓✓ | 31 |
for (i = 0; i < fmt_ctx->nb_programs; i++) { |
2874 |
3 |
AVProgram *program = fmt_ctx->programs[i]; |
|
2875 |
✗✓ | 3 |
if (!program) |
2876 |
continue; |
||
2877 |
3 |
ret = show_program(w, ifile, program); |
|
2878 |
✗✓ | 3 |
if (ret < 0) |
2879 |
break; |
||
2880 |
} |
||
2881 |
28 |
writer_print_section_footer(w); |
|
2882 |
28 |
return ret; |
|
2883 |
} |
||
2884 |
|||
2885 |
3 |
static int show_chapters(WriterContext *w, InputFile *ifile) |
|
2886 |
{ |
||
2887 |
3 |
AVFormatContext *fmt_ctx = ifile->fmt_ctx; |
|
2888 |
3 |
int i, ret = 0; |
|
2889 |
|||
2890 |
3 |
writer_print_section_header(w, SECTION_ID_CHAPTERS); |
|
2891 |
✓✓ | 16 |
for (i = 0; i < fmt_ctx->nb_chapters; i++) { |
2892 |
13 |
AVChapter *chapter = fmt_ctx->chapters[i]; |
|
2893 |
|||
2894 |
13 |
writer_print_section_header(w, SECTION_ID_CHAPTER); |
|
2895 |
13 |
print_int("id", chapter->id); |
|
2896 |
13 |
print_q ("time_base", chapter->time_base, '/'); |
|
2897 |
13 |
print_int("start", chapter->start); |
|
2898 |
13 |
print_time("start_time", chapter->start, &chapter->time_base); |
|
2899 |
13 |
print_int("end", chapter->end); |
|
2900 |
13 |
print_time("end_time", chapter->end, &chapter->time_base); |
|
2901 |
✓✗ | 13 |
if (do_show_chapter_tags) |
2902 |
13 |
ret = show_tags(w, chapter->metadata, SECTION_ID_CHAPTER_TAGS); |
|
2903 |
13 |
writer_print_section_footer(w); |
|
2904 |
} |
||
2905 |
3 |
writer_print_section_footer(w); |
|
2906 |
|||
2907 |
3 |
return ret; |
|
2908 |
} |
||
2909 |
|||
2910 |
20 |
static int show_format(WriterContext *w, InputFile *ifile) |
|
2911 |
{ |
||
2912 |
20 |
AVFormatContext *fmt_ctx = ifile->fmt_ctx; |
|
2913 |
char val_str[128]; |
||
2914 |
✓✗ | 20 |
int64_t size = fmt_ctx->pb ? avio_size(fmt_ctx->pb) : -1; |
2915 |
20 |
int ret = 0; |
|
2916 |
|||
2917 |
20 |
writer_print_section_header(w, SECTION_ID_FORMAT); |
|
2918 |
20 |
print_str_validate("filename", fmt_ctx->url); |
|
2919 |
20 |
print_int("nb_streams", fmt_ctx->nb_streams); |
|
2920 |
20 |
print_int("nb_programs", fmt_ctx->nb_programs); |
|
2921 |
20 |
print_str("format_name", fmt_ctx->iformat->name); |
|
2922 |
✓✓ | 20 |
if (!do_bitexact) { |
2923 |
✓✗ | 5 |
if (fmt_ctx->iformat->long_name) print_str ("format_long_name", fmt_ctx->iformat->long_name); |
2924 |
else print_str_opt("format_long_name", "unknown"); |
||
2925 |
} |
||
2926 |
20 |
print_time("start_time", fmt_ctx->start_time, &AV_TIME_BASE_Q); |
|
2927 |
20 |
print_time("duration", fmt_ctx->duration, &AV_TIME_BASE_Q); |
|
2928 |
✓✗ | 20 |
if (size >= 0) print_val ("size", size, unit_byte_str); |
2929 |
else print_str_opt("size", "N/A"); |
||
2930 |
✓✗ | 20 |
if (fmt_ctx->bit_rate > 0) print_val ("bit_rate", fmt_ctx->bit_rate, unit_bit_per_second_str); |
2931 |
else print_str_opt("bit_rate", "N/A"); |
||
2932 |
20 |
print_int("probe_score", fmt_ctx->probe_score); |
|
2933 |
✓✓ | 20 |
if (do_show_format_tags) |
2934 |
12 |
ret = show_tags(w, fmt_ctx->metadata, SECTION_ID_FORMAT_TAGS); |
|
2935 |
|||
2936 |
20 |
writer_print_section_footer(w); |
|
2937 |
20 |
fflush(stdout); |
|
2938 |
20 |
return ret; |
|
2939 |
} |
||
2940 |
|||
2941 |
static void show_error(WriterContext *w, int err) |
||
2942 |
{ |
||
2943 |
char errbuf[128]; |
||
2944 |
const char *errbuf_ptr = errbuf; |
||
2945 |
|||
2946 |
if (av_strerror(err, errbuf, sizeof(errbuf)) < 0) |
||
2947 |
errbuf_ptr = strerror(AVUNERROR(err)); |
||
2948 |
|||
2949 |
writer_print_section_header(w, SECTION_ID_ERROR); |
||
2950 |
print_int("code", err); |
||
2951 |
print_str("string", errbuf_ptr); |
||
2952 |
writer_print_section_footer(w); |
||
2953 |
} |
||
2954 |
|||
2955 |
76 |
static int open_input_file(InputFile *ifile, const char *filename, |
|
2956 |
const char *print_filename) |
||
2957 |
{ |
||
2958 |
int err, i; |
||
2959 |
76 |
AVFormatContext *fmt_ctx = NULL; |
|
2960 |
76 |
AVDictionaryEntry *t = NULL; |
|
2961 |
76 |
int scan_all_pmts_set = 0; |
|
2962 |
|||
2963 |
76 |
fmt_ctx = avformat_alloc_context(); |
|
2964 |
✗✓ | 76 |
if (!fmt_ctx) { |
2965 |
print_error(filename, AVERROR(ENOMEM)); |
||
2966 |
exit_program(1); |
||
2967 |
} |
||
2968 |
|||
2969 |
✓✗ | 76 |
if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) { |
2970 |
76 |
av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE); |
|
2971 |
76 |
scan_all_pmts_set = 1; |
|
2972 |
} |
||
2973 |
✗✓ | 76 |
if ((err = avformat_open_input(&fmt_ctx, filename, |
2974 |
iformat, &format_opts)) < 0) { |
||
2975 |
print_error(filename, err); |
||
2976 |
return err; |
||
2977 |
} |
||
2978 |
✓✓ | 76 |
if (print_filename) { |
2979 |
7 |
av_freep(&fmt_ctx->url); |
|
2980 |
7 |
fmt_ctx->url = av_strdup(print_filename); |
|
2981 |
} |
||
2982 |
76 |
ifile->fmt_ctx = fmt_ctx; |
|
2983 |
✓✗ | 76 |
if (scan_all_pmts_set) |
2984 |
76 |
av_dict_set(&format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE); |
|
2985 |
✗✓ | 76 |
while ((t = av_dict_get(format_opts, "", t, AV_DICT_IGNORE_SUFFIX))) |
2986 |
av_log(NULL, AV_LOG_WARNING, "Option %s skipped - not known to demuxer.\n", t->key); |
||
2987 |
|||
2988 |
✓✗ | 76 |
if (find_stream_info) { |
2989 |
76 |
AVDictionary **opts = setup_find_stream_info_opts(fmt_ctx, codec_opts); |
|
2990 |
76 |
int orig_nb_streams = fmt_ctx->nb_streams; |
|
2991 |
|||
2992 |
76 |
err = avformat_find_stream_info(fmt_ctx, opts); |
|
2993 |
|||
2994 |
✓✓ | 190 |
for (i = 0; i < orig_nb_streams; i++) |
2995 |
114 |
av_dict_free(&opts[i]); |
|
2996 |
76 |
av_freep(&opts); |
|
2997 |
|||
2998 |
✗✓ | 76 |
if (err < 0) { |
2999 |
print_error(filename, err); |
||
3000 |
return err; |
||
3001 |
} |
||
3002 |
} |
||
3003 |
|||
3004 |
76 |
av_dump_format(fmt_ctx, 0, filename, 0); |
|
3005 |
|||
3006 |
76 |
ifile->streams = av_mallocz_array(fmt_ctx->nb_streams, |
|
3007 |
sizeof(*ifile->streams)); |
||
3008 |
✗✓ | 76 |
if (!ifile->streams) |
3009 |
exit(1); |
||
3010 |
76 |
ifile->nb_streams = fmt_ctx->nb_streams; |
|
3011 |
|||
3012 |
/* bind a decoder to each input stream */ |
||
3013 |
✓✓ | 197 |
for (i = 0; i < fmt_ctx->nb_streams; i++) { |
3014 |
121 |
InputStream *ist = &ifile->streams[i]; |
|
3015 |
121 |
AVStream *stream = fmt_ctx->streams[i]; |
|
3016 |
AVCodec *codec; |
||
3017 |
|||
3018 |
121 |
ist->st = stream; |
|
3019 |
|||
3020 |
✗✓ | 121 |
if (stream->codecpar->codec_id == AV_CODEC_ID_PROBE) { |
3021 |
av_log(NULL, AV_LOG_WARNING, |
||
3022 |
"Failed to probe codec for input stream %d\n", |
||
3023 |
stream->index); |
||
3024 |
continue; |
||
3025 |
} |
||
3026 |
|||
3027 |
121 |
codec = avcodec_find_decoder(stream->codecpar->codec_id); |
|
3028 |
✓✓ | 121 |
if (!codec) { |
3029 |
7 |
av_log(NULL, AV_LOG_WARNING, |
|
3030 |
"Unsupported codec with id %d for input stream %d\n", |
||
3031 |
7 |
stream->codecpar->codec_id, stream->index); |
|
3032 |
7 |
continue; |
|
3033 |
} |
||
3034 |
{ |
||
3035 |
114 |
AVDictionary *opts = filter_codec_opts(codec_opts, stream->codecpar->codec_id, |
|
3036 |
fmt_ctx, stream, codec); |
||
3037 |
|||
3038 |
114 |
ist->dec_ctx = avcodec_alloc_context3(codec); |
|
3039 |
✗✓ | 114 |
if (!ist->dec_ctx) |
3040 |
exit(1); |
||
3041 |
|||
3042 |
114 |
err = avcodec_parameters_to_context(ist->dec_ctx, stream->codecpar); |
|
3043 |
✗✓ | 114 |
if (err < 0) |
3044 |
exit(1); |
||
3045 |
|||
3046 |
✗✓ | 114 |
if (do_show_log) { |
3047 |
// For loging it is needed to disable at least frame threads as otherwise |
||
3048 |
// the log information would need to be reordered and matches up to contexts and frames |
||
3049 |
// That is in fact possible but not trivial |
||
3050 |
av_dict_set(&codec_opts, "threads", "1", 0); |
||
3051 |
} |
||
3052 |
|||
3053 |
114 |
ist->dec_ctx->pkt_timebase = stream->time_base; |
|
3054 |
114 |
ist->dec_ctx->framerate = stream->avg_frame_rate; |
|
3055 |
#if FF_API_LAVF_AVCTX |
||
3056 |
114 |
ist->dec_ctx->properties = stream->codec->properties; |
|
3057 |
114 |
ist->dec_ctx->coded_width = stream->codec->coded_width; |
|
3058 |
114 |
ist->dec_ctx->coded_height = stream->codec->coded_height; |
|
3059 |
#endif |
||
3060 |
|||
3061 |
✗✓ | 114 |
if (avcodec_open2(ist->dec_ctx, codec, &opts) < 0) { |
3062 |
av_log(NULL, AV_LOG_WARNING, "Could not open codec for input stream %d\n", |
||
3063 |
stream->index); |
||
3064 |
exit(1); |
||
3065 |
} |
||
3066 |
|||
3067 |
✗✓ | 114 |
if ((t = av_dict_get(opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) { |
3068 |
av_log(NULL, AV_LOG_ERROR, "Option %s for input stream %d not found\n", |
||
3069 |
t->key, stream->index); |
||
3070 |
return AVERROR_OPTION_NOT_FOUND; |
||
3071 |
} |
||
3072 |
} |
||
3073 |
} |
||
3074 |
|||
3075 |
76 |
ifile->fmt_ctx = fmt_ctx; |
|
3076 |
76 |
return 0; |
|
3077 |
} |
||
3078 |
|||
3079 |
76 |
static void close_input_file(InputFile *ifile) |
|
3080 |
{ |
||
3081 |
int i; |
||
3082 |
|||
3083 |
/* close decoder for each stream */ |
||
3084 |
✓✓ | 197 |
for (i = 0; i < ifile->nb_streams; i++) |
3085 |
✓✓ | 121 |
if (ifile->streams[i].st->codecpar->codec_id != AV_CODEC_ID_NONE) |
3086 |
117 |
avcodec_free_context(&ifile->streams[i].dec_ctx); |
|
3087 |
|||
3088 |
76 |
av_freep(&ifile->streams); |
|
3089 |
76 |
ifile->nb_streams = 0; |
|
3090 |
|||
3091 |
76 |
avformat_close_input(&ifile->fmt_ctx); |
|
3092 |
76 |
} |
|
3093 |
|||
3094 |
76 |
static int probe_file(WriterContext *wctx, const char *filename, |
|
3095 |
const char *print_filename) |
||
3096 |
{ |
||
3097 |
76 |
InputFile ifile = { 0 }; |
|
3098 |
int ret, i; |
||
3099 |
int section_id; |
||
3100 |
|||
3101 |
✓✓✗✓ |
76 |
do_read_frames = do_show_frames || do_count_frames; |
3102 |
✓✓✗✓ |
76 |
do_read_packets = do_show_packets || do_count_packets; |
3103 |
|||
3104 |
76 |
ret = open_input_file(&ifile, filename, print_filename); |
|
3105 |
✗✓ | 76 |
if (ret < 0) |
3106 |
goto end; |
||
3107 |
|||
3108 |
#define CHECK_END if (ret < 0) goto end |
||
3109 |
|||
3110 |
76 |
nb_streams = ifile.fmt_ctx->nb_streams; |
|
3111 |
✗✓ | 76 |
REALLOCZ_ARRAY_STREAM(nb_streams_frames,0,ifile.fmt_ctx->nb_streams); |
3112 |
✗✓ | 76 |
REALLOCZ_ARRAY_STREAM(nb_streams_packets,0,ifile.fmt_ctx->nb_streams); |
3113 |
✗✓ | 76 |
REALLOCZ_ARRAY_STREAM(selected_streams,0,ifile.fmt_ctx->nb_streams); |
3114 |
|||
3115 |
✓✓ | 197 |
for (i = 0; i < ifile.fmt_ctx->nb_streams; i++) { |
3116 |
✓✓ | 121 |
if (stream_specifier) { |
3117 |
31 |
ret = avformat_match_stream_specifier(ifile.fmt_ctx, |
|
3118 |
31 |
ifile.fmt_ctx->streams[i], |
|
3119 |
stream_specifier); |
||
3120 |
✗✓ | 31 |
CHECK_END; |
3121 |
else |
||
3122 |
31 |
selected_streams[i] = ret; |
|
3123 |
31 |
ret = 0; |
|
3124 |
} else { |
||
3125 |
90 |
selected_streams[i] = 1; |
|
3126 |
} |
||
3127 |
✓✓ | 121 |
if (!selected_streams[i]) |
3128 |
8 |
ifile.fmt_ctx->streams[i]->discard = AVDISCARD_ALL; |
|
3129 |
} |
||
3130 |
|||
3131 |
✓✓✓✓ |
76 |
if (do_read_frames || do_read_packets) { |
3132 |
✓✓✓✓ |
47 |
if (do_show_frames && do_show_packets && |
3133 |
✓✓ | 9 |
wctx->writer->flags & WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER) |
3134 |
4 |
section_id = SECTION_ID_PACKETS_AND_FRAMES; |
|
3135 |
✓✓✓✓ |
43 |
else if (do_show_packets && !do_show_frames) |
3136 |
13 |
section_id = SECTION_ID_PACKETS; |
|
3137 |
else // (!do_show_packets && do_show_frames) |
||
3138 |
30 |
section_id = SECTION_ID_FRAMES; |
|
3139 |
✓✓✓✗ |
47 |
if (do_show_frames || do_show_packets) |
3140 |
47 |
writer_print_section_header(wctx, section_id); |
|
3141 |
47 |
ret = read_packets(wctx, &ifile); |
|
3142 |
✓✓✓✗ |
47 |
if (do_show_frames || do_show_packets) |
3143 |
47 |
writer_print_section_footer(wctx); |
|
3144 |
✗✓ | 47 |
CHECK_END; |
3145 |
} |
||
3146 |
|||
3147 |
✓✓ | 76 |
if (do_show_programs) { |
3148 |
28 |
ret = show_programs(wctx, &ifile); |
|
3149 |
✗✓ | 28 |
CHECK_END; |
3150 |
} |
||
3151 |
|||
3152 |
✓✓ | 76 |
if (do_show_streams) { |
3153 |
45 |
ret = show_streams(wctx, &ifile); |
|
3154 |
✗✓ | 45 |
CHECK_END; |
3155 |
} |
||
3156 |
✓✓ | 76 |
if (do_show_chapters) { |
3157 |
3 |
ret = show_chapters(wctx, &ifile); |
|
3158 |
✗✓ | 3 |
CHECK_END; |
3159 |
} |
||
3160 |
✓✓ | 76 |
if (do_show_format) { |
3161 |
20 |
ret = show_format(wctx, &ifile); |
|
3162 |
✓✗ | 20 |
CHECK_END; |
3163 |
} |
||
3164 |
|||
3165 |
76 |
end: |
|
3166 |
✓✗ | 76 |
if (ifile.fmt_ctx) |
3167 |
76 |
close_input_file(&ifile); |
|
3168 |
76 |
av_freep(&nb_streams_frames); |
|
3169 |
76 |
av_freep(&nb_streams_packets); |
|
3170 |
76 |
av_freep(&selected_streams); |
|
3171 |
|||
3172 |
76 |
return ret; |
|
3173 |
} |
||
3174 |
|||
3175 |
static void show_usage(void) |
||
3176 |
{ |
||
3177 |
av_log(NULL, AV_LOG_INFO, "Simple multimedia streams analyzer\n"); |
||
3178 |
av_log(NULL, AV_LOG_INFO, "usage: %s [OPTIONS] [INPUT_FILE]\n", program_name); |
||
3179 |
av_log(NULL, AV_LOG_INFO, "\n"); |
||
3180 |
} |
||
3181 |
|||
3182 |
static void ffprobe_show_program_version(WriterContext *w) |
||
3183 |
{ |
||
3184 |
AVBPrint pbuf; |
||
3185 |
av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); |
||
3186 |
|||
3187 |
writer_print_section_header(w, SECTION_ID_PROGRAM_VERSION); |
||
3188 |
print_str("version", FFMPEG_VERSION); |
||
3189 |
print_fmt("copyright", "Copyright (c) %d-%d the FFmpeg developers", |
||
3190 |
program_birth_year, CONFIG_THIS_YEAR); |
||
3191 |
print_str("compiler_ident", CC_IDENT); |
||
3192 |
print_str("configuration", FFMPEG_CONFIGURATION); |
||
3193 |
writer_print_section_footer(w); |
||
3194 |
|||
3195 |
av_bprint_finalize(&pbuf, NULL); |
||
3196 |
} |
||
3197 |
|||
3198 |
#define SHOW_LIB_VERSION(libname, LIBNAME) \ |
||
3199 |
do { \ |
||
3200 |
if (CONFIG_##LIBNAME) { \ |
||
3201 |
unsigned int version = libname##_version(); \ |
||
3202 |
writer_print_section_header(w, SECTION_ID_LIBRARY_VERSION); \ |
||
3203 |
print_str("name", "lib" #libname); \ |
||
3204 |
print_int("major", LIB##LIBNAME##_VERSION_MAJOR); \ |
||
3205 |
print_int("minor", LIB##LIBNAME##_VERSION_MINOR); \ |
||
3206 |
print_int("micro", LIB##LIBNAME##_VERSION_MICRO); \ |
||
3207 |
print_int("version", version); \ |
||
3208 |
print_str("ident", LIB##LIBNAME##_IDENT); \ |
||
3209 |
writer_print_section_footer(w); \ |
||
3210 |
} \ |
||
3211 |
} while (0) |
||
3212 |
|||
3213 |
static void ffprobe_show_library_versions(WriterContext *w) |
||
3214 |
{ |
||
3215 |
writer_print_section_header(w, SECTION_ID_LIBRARY_VERSIONS); |
||
3216 |
SHOW_LIB_VERSION(avutil, AVUTIL); |
||
3217 |
SHOW_LIB_VERSION(avcodec, AVCODEC); |
||
3218 |
SHOW_LIB_VERSION(avformat, AVFORMAT); |
||
3219 |
SHOW_LIB_VERSION(avdevice, AVDEVICE); |
||
3220 |
SHOW_LIB_VERSION(avfilter, AVFILTER); |
||
3221 |
SHOW_LIB_VERSION(swscale, SWSCALE); |
||
3222 |
SHOW_LIB_VERSION(swresample, SWRESAMPLE); |
||
3223 |
SHOW_LIB_VERSION(postproc, POSTPROC); |
||
3224 |
writer_print_section_footer(w); |
||
3225 |
} |
||
3226 |
|||
3227 |
#define PRINT_PIX_FMT_FLAG(flagname, name) \ |
||
3228 |
do { \ |
||
3229 |
print_int(name, !!(pixdesc->flags & AV_PIX_FMT_FLAG_##flagname)); \ |
||
3230 |
} while (0) |
||
3231 |
|||
3232 |
static void ffprobe_show_pixel_formats(WriterContext *w) |
||
3233 |
{ |
||
3234 |
const AVPixFmtDescriptor *pixdesc = NULL; |
||
3235 |
int i, n; |
||
3236 |
|||
3237 |
writer_print_section_header(w, SECTION_ID_PIXEL_FORMATS); |
||
3238 |
while (pixdesc = av_pix_fmt_desc_next(pixdesc)) { |
||
3239 |
writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT); |
||
3240 |
print_str("name", pixdesc->name); |
||
3241 |
print_int("nb_components", pixdesc->nb_components); |
||
3242 |
if ((pixdesc->nb_components >= 3) && !(pixdesc->flags & AV_PIX_FMT_FLAG_RGB)) { |
||
3243 |
print_int ("log2_chroma_w", pixdesc->log2_chroma_w); |
||
3244 |
print_int ("log2_chroma_h", pixdesc->log2_chroma_h); |
||
3245 |
} else { |
||
3246 |
print_str_opt("log2_chroma_w", "N/A"); |
||
3247 |
print_str_opt("log2_chroma_h", "N/A"); |
||
3248 |
} |
||
3249 |
n = av_get_bits_per_pixel(pixdesc); |
||
3250 |
if (n) print_int ("bits_per_pixel", n); |
||
3251 |
else print_str_opt("bits_per_pixel", "N/A"); |
||
3252 |
if (do_show_pixel_format_flags) { |
||
3253 |
writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_FLAGS); |
||
3254 |
PRINT_PIX_FMT_FLAG(BE, "big_endian"); |
||
3255 |
PRINT_PIX_FMT_FLAG(PAL, "palette"); |
||
3256 |
PRINT_PIX_FMT_FLAG(BITSTREAM, "bitstream"); |
||
3257 |
PRINT_PIX_FMT_FLAG(HWACCEL, "hwaccel"); |
||
3258 |
PRINT_PIX_FMT_FLAG(PLANAR, "planar"); |
||
3259 |
PRINT_PIX_FMT_FLAG(RGB, "rgb"); |
||
3260 |
#if FF_API_PSEUDOPAL |
||
3261 |
PRINT_PIX_FMT_FLAG(PSEUDOPAL, "pseudopal"); |
||
3262 |
#endif |
||
3263 |
PRINT_PIX_FMT_FLAG(ALPHA, "alpha"); |
||
3264 |
writer_print_section_footer(w); |
||
3265 |
} |
||
3266 |
if (do_show_pixel_format_components && (pixdesc->nb_components > 0)) { |
||
3267 |
writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_COMPONENTS); |
||
3268 |
for (i = 0; i < pixdesc->nb_components; i++) { |
||
3269 |
writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_COMPONENT); |
||
3270 |
print_int("index", i + 1); |
||
3271 |
print_int("bit_depth", pixdesc->comp[i].depth); |
||
3272 |
writer_print_section_footer(w); |
||
3273 |
} |
||
3274 |
writer_print_section_footer(w); |
||
3275 |
} |
||
3276 |
writer_print_section_footer(w); |
||
3277 |
} |
||
3278 |
writer_print_section_footer(w); |
||
3279 |
} |
||
3280 |
|||
3281 |
12 |
static int opt_format(void *optctx, const char *opt, const char *arg) |
|
3282 |
{ |
||
3283 |
12 |
iformat = av_find_input_format(arg); |
|
3284 |
✗✓ | 12 |
if (!iformat) { |
3285 |
av_log(NULL, AV_LOG_ERROR, "Unknown input format: %s\n", arg); |
||
3286 |
return AVERROR(EINVAL); |
||
3287 |
} |
||
3288 |
12 |
return 0; |
|
3289 |
} |
||
3290 |
|||
3291 |
534 |
static inline void mark_section_show_entries(SectionID section_id, |
|
3292 |
int show_all_entries, AVDictionary *entries) |
||
3293 |
{ |
||
3294 |
534 |
struct section *section = §ions[section_id]; |
|
3295 |
|||
3296 |
534 |
section->show_all_entries = show_all_entries; |
|
3297 |
✓✓ | 534 |
if (show_all_entries) { |
3298 |
SectionID *id; |
||
3299 |
✓✓ | 807 |
for (id = section->children_ids; *id != -1; id++) |
3300 |
357 |
mark_section_show_entries(*id, show_all_entries, entries); |
|
3301 |
} else { |
||
3302 |
84 |
av_dict_copy(§ion->entries_to_show, entries, 0); |
|
3303 |
} |
||
3304 |
534 |
} |
|
3305 |
|||
3306 |
88 |
static int match_section(const char *section_name, |
|
3307 |
int show_all_entries, AVDictionary *entries) |
||
3308 |
{ |
||
3309 |
88 |
int i, ret = 0; |
|
3310 |
|||
3311 |
✓✓ | 3960 |
for (i = 0; i < FF_ARRAY_ELEMS(sections); i++) { |
3312 |
3872 |
const struct section *section = §ions[i]; |
|
3313 |
✓✓ | 3872 |
if (!strcmp(section_name, section->name) || |
3314 |
✓✓✓✓ |
3780 |
(section->unique_name && !strcmp(section_name, section->unique_name))) { |
3315 |
116 |
av_log(NULL, AV_LOG_DEBUG, |
|
3316 |
"'%s' matches section with unique name '%s'\n", section_name, |
||
3317 |
116 |
(char *)av_x_if_null(section->unique_name, section->name)); |
|
3318 |
116 |
ret++; |
|
3319 |
116 |
mark_section_show_entries(section->id, show_all_entries, entries); |
|
3320 |
} |
||
3321 |
} |
||
3322 |
88 |
return ret; |
|
3323 |
} |
||
3324 |
|||
3325 |
50 |
static int opt_show_entries(void *optctx, const char *opt, const char *arg) |
|
3326 |
{ |
||
3327 |
50 |
const char *p = arg; |
|
3328 |
50 |
int ret = 0; |
|
3329 |
|||
3330 |
✓✓ | 138 |
while (*p) { |
3331 |
88 |
AVDictionary *entries = NULL; |
|
3332 |
88 |
char *section_name = av_get_token(&p, "=:"); |
|
3333 |
88 |
int show_all_entries = 0; |
|
3334 |
|||
3335 |
✗✓ | 88 |
if (!section_name) { |
3336 |
av_log(NULL, AV_LOG_ERROR, |
||
3337 |
"Missing section name for option '%s'\n", opt); |
||
3338 |
return AVERROR(EINVAL); |
||
3339 |
} |
||
3340 |
|||
3341 |
✓✓ | 88 |
if (*p == '=') { |
3342 |
60 |
p++; |
|
3343 |
✓✓✓✓ |
180 |
while (*p && *p != ':') { |
3344 |
120 |
char *entry = av_get_token(&p, ",:"); |
|
3345 |
✗✓ | 120 |
if (!entry) |
3346 |
break; |
||
3347 |
120 |
av_log(NULL, AV_LOG_VERBOSE, |
|
3348 |
"Adding '%s' to the entries to show in section '%s'\n", |
||
3349 |
entry, section_name); |
||
3350 |
120 |
av_dict_set(&entries, entry, "", AV_DICT_DONT_STRDUP_KEY); |
|
3351 |
✓✓ | 120 |
if (*p == ',') |
3352 |
60 |
p++; |
|
3353 |
} |
||
3354 |
} else { |
||
3355 |
28 |
show_all_entries = 1; |
|
3356 |
} |
||
3357 |
|||
3358 |
88 |
ret = match_section(section_name, show_all_entries, entries); |
|
3359 |
✗✓ | 88 |
if (ret == 0) { |
3360 |
av_log(NULL, AV_LOG_ERROR, "No match for section '%s'\n", section_name); |
||
3361 |
ret = AVERROR(EINVAL); |
||
3362 |
} |
||
3363 |
88 |
av_dict_free(&entries); |
|
3364 |
88 |
av_free(section_name); |
|
3365 |
|||
3366 |
✗✓ | 88 |
if (ret <= 0) |
3367 |
break; |
||
3368 |
✓✓ | 88 |
if (*p) |
3369 |
38 |
p++; |
|
3370 |
} |
||
3371 |
|||
3372 |
50 |
return ret; |
|
3373 |
} |
||
3374 |
|||
3375 |
static int opt_show_format_entry(void *optctx, const char *opt, const char *arg) |
||
3376 |
{ |
||
3377 |
char *buf = av_asprintf("format=%s", arg); |
||
3378 |
int ret; |
||
3379 |
|||
3380 |
if (!buf) |
||
3381 |
return AVERROR(ENOMEM); |
||
3382 |
|||
3383 |
av_log(NULL, AV_LOG_WARNING, |
||
3384 |
"Option '%s' is deprecated, use '-show_entries format=%s' instead\n", |
||
3385 |
opt, arg); |
||
3386 |
ret = opt_show_entries(optctx, opt, buf); |
||
3387 |
av_free(buf); |
||
3388 |
return ret; |
||
3389 |
} |
||
3390 |
|||
3391 |
76 |
static void opt_input_file(void *optctx, const char *arg) |
|
3392 |
{ |
||
3393 |
✗✓ | 76 |
if (input_filename) { |
3394 |
av_log(NULL, AV_LOG_ERROR, |
||
3395 |
"Argument '%s' provided as input filename, but '%s' was already specified.\n", |
||
3396 |
arg, input_filename); |
||
3397 |
exit_program(1); |
||
3398 |
} |
||
3399 |
✗✓ | 76 |
if (!strcmp(arg, "-")) |
3400 |
arg = "pipe:"; |
||
3401 |
76 |
input_filename = arg; |
|
3402 |
76 |
} |
|
3403 |
|||
3404 |
7 |
static int opt_input_file_i(void *optctx, const char *opt, const char *arg) |
|
3405 |
{ |
||
3406 |
7 |
opt_input_file(optctx, arg); |
|
3407 |
7 |
return 0; |
|
3408 |
} |
||
3409 |
|||
3410 |
7 |
static int opt_print_filename(void *optctx, const char *opt, const char *arg) |
|
3411 |
{ |
||
3412 |
7 |
print_input_filename = arg; |
|
3413 |
7 |
return 0; |
|
3414 |
} |
||
3415 |
|||
3416 |
void show_help_default(const char *opt, const char *arg) |
||
3417 |
{ |
||
3418 |
av_log_set_callback(log_callback_help); |
||
3419 |
show_usage(); |
||
3420 |
show_help_options(options, "Main options:", 0, 0, 0); |
||
3421 |
printf("\n"); |
||
3422 |
|||
3423 |
show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM); |
||
3424 |
show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM); |
||
3425 |
} |
||
3426 |
|||
3427 |
/** |
||
3428 |
* Parse interval specification, according to the format: |
||
3429 |
* INTERVAL ::= [START|+START_OFFSET][%[END|+END_OFFSET]] |
||
3430 |
* INTERVALS ::= INTERVAL[,INTERVALS] |
||
3431 |
*/ |
||
3432 |
static int parse_read_interval(const char *interval_spec, |
||
3433 |
ReadInterval *interval) |
||
3434 |
{ |
||
3435 |
int ret = 0; |
||
3436 |
char *next, *p, *spec = av_strdup(interval_spec); |
||
3437 |
if (!spec) |
||
3438 |
return AVERROR(ENOMEM); |
||
3439 |
|||
3440 |
if (!*spec) { |
||
3441 |