2 * Various pretty-printing functions for use within FFmpeg
3 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "libavutil/channel_layout.h"
26 #include "libavutil/display.h"
27 #include "libavutil/intreadwrite.h"
28 #include "libavutil/log.h"
29 #include "libavutil/mathematics.h"
30 #include "libavutil/opt.h"
31 #include "libavutil/avstring.h"
32 #include "libavutil/replaygain.h"
33 #include "libavutil/stereo3d.h"
37 #define HEXDUMP_PRINT(...) \
40 av_log(avcl, level, __VA_ARGS__); \
42 fprintf(f, __VA_ARGS__); \
45 static void hex_dump_internal(void *avcl
, FILE *f
, int level
,
46 const uint8_t *buf
, int size
)
50 for (i
= 0; i
< size
; i
+= 16) {
54 HEXDUMP_PRINT("%08x ", i
);
55 for (j
= 0; j
< 16; j
++) {
57 HEXDUMP_PRINT(" %02x", buf
[i
+ j
]);
62 for (j
= 0; j
< len
; j
++) {
64 if (c
< ' ' || c
> '~')
66 HEXDUMP_PRINT("%c", c
);
72 void av_hex_dump(FILE *f
, const uint8_t *buf
, int size
)
74 hex_dump_internal(NULL
, f
, 0, buf
, size
);
77 void av_hex_dump_log(void *avcl
, int level
, const uint8_t *buf
, int size
)
79 hex_dump_internal(avcl
, NULL
, level
, buf
, size
);
82 static void pkt_dump_internal(void *avcl
, FILE *f
, int level
, const AVPacket
*pkt
,
83 int dump_payload
, AVRational time_base
)
85 HEXDUMP_PRINT("stream #%d:\n", pkt
->stream_index
);
86 HEXDUMP_PRINT(" keyframe=%d\n", (pkt
->flags
& AV_PKT_FLAG_KEY
) != 0);
87 HEXDUMP_PRINT(" duration=%0.3f\n", pkt
->duration
* av_q2d(time_base
));
88 /* DTS is _always_ valid after av_read_frame() */
89 HEXDUMP_PRINT(" dts=");
90 if (pkt
->dts
== AV_NOPTS_VALUE
)
93 HEXDUMP_PRINT("%0.3f", pkt
->dts
* av_q2d(time_base
));
94 /* PTS may not be known if B-frames are present. */
95 HEXDUMP_PRINT(" pts=");
96 if (pkt
->pts
== AV_NOPTS_VALUE
)
99 HEXDUMP_PRINT("%0.3f", pkt
->pts
* av_q2d(time_base
));
101 HEXDUMP_PRINT(" size=%d\n", pkt
->size
);
103 av_hex_dump(f
, pkt
->data
, pkt
->size
);
106 void av_pkt_dump2(FILE *f
, const AVPacket
*pkt
, int dump_payload
, const AVStream
*st
)
108 pkt_dump_internal(NULL
, f
, 0, pkt
, dump_payload
, st
->time_base
);
111 void av_pkt_dump_log2(void *avcl
, int level
, const AVPacket
*pkt
, int dump_payload
,
114 pkt_dump_internal(avcl
, NULL
, level
, pkt
, dump_payload
, st
->time_base
);
118 static void print_fps(double d
, const char *postfix
)
120 uint64_t v
= lrintf(d
* 100);
122 av_log(NULL
, AV_LOG_INFO
, "%3.2f %s", d
, postfix
);
123 else if (v
% (100 * 1000))
124 av_log(NULL
, AV_LOG_INFO
, "%1.0f %s", d
, postfix
);
126 av_log(NULL
, AV_LOG_INFO
, "%1.0fk %s", d
/ 1000, postfix
);
129 static void dump_metadata(void *ctx
, AVDictionary
*m
, const char *indent
)
131 if (m
&& !(av_dict_count(m
) == 1 && av_dict_get(m
, "language", NULL
, 0))) {
132 AVDictionaryEntry
*tag
= NULL
;
134 av_log(ctx
, AV_LOG_INFO
, "%sMetadata:\n", indent
);
135 while ((tag
= av_dict_get(m
, "", tag
, AV_DICT_IGNORE_SUFFIX
)))
136 if (strcmp("language", tag
->key
)) {
137 const char *p
= tag
->value
;
138 av_log(ctx
, AV_LOG_INFO
,
139 "%s %-16s: ", indent
, tag
->key
);
142 size_t len
= strcspn(p
, "\x8\xa\xb\xc\xd");
143 av_strlcpy(tmp
, p
, FFMIN(sizeof(tmp
), len
+1));
144 av_log(ctx
, AV_LOG_INFO
, "%s", tmp
);
146 if (*p
== 0xd) av_log(ctx
, AV_LOG_INFO
, " ");
147 if (*p
== 0xa) av_log(ctx
, AV_LOG_INFO
, "\n%s %-16s: ", indent
, "");
150 av_log(ctx
, AV_LOG_INFO
, "\n");
155 /* param change side data*/
156 static void dump_paramchange(void *ctx
, AVPacketSideData
*sd
)
159 const uint8_t *data
= sd
->data
;
160 uint32_t flags
, channels
, sample_rate
, width
, height
;
163 if (!data
|| sd
->size
< 4)
166 flags
= AV_RL32(data
);
170 if (flags
& AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT
) {
173 channels
= AV_RL32(data
);
176 av_log(ctx
, AV_LOG_INFO
, "channel count %"PRIu32
", ", channels
);
178 if (flags
& AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT
) {
181 layout
= AV_RL64(data
);
184 av_log(ctx
, AV_LOG_INFO
,
185 "channel layout: %s, ", av_get_channel_name(layout
));
187 if (flags
& AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE
) {
190 sample_rate
= AV_RL32(data
);
193 av_log(ctx
, AV_LOG_INFO
, "sample_rate %"PRIu32
", ", sample_rate
);
195 if (flags
& AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS
) {
198 width
= AV_RL32(data
);
201 height
= AV_RL32(data
);
204 av_log(ctx
, AV_LOG_INFO
, "width %"PRIu32
" height %"PRIu32
, width
, height
);
209 av_log(ctx
, AV_LOG_INFO
, "unknown param");
212 /* replaygain side data*/
213 static void print_gain(void *ctx
, const char *str
, int32_t gain
)
215 av_log(ctx
, AV_LOG_INFO
, "%s - ", str
);
216 if (gain
== INT32_MIN
)
217 av_log(ctx
, AV_LOG_INFO
, "unknown");
219 av_log(ctx
, AV_LOG_INFO
, "%f", gain
/ 100000.0f
);
220 av_log(ctx
, AV_LOG_INFO
, ", ");
223 static void print_peak(void *ctx
, const char *str
, uint32_t peak
)
225 av_log(ctx
, AV_LOG_INFO
, "%s - ", str
);
227 av_log(ctx
, AV_LOG_INFO
, "unknown");
229 av_log(ctx
, AV_LOG_INFO
, "%f", (float) peak
/ UINT32_MAX
);
230 av_log(ctx
, AV_LOG_INFO
, ", ");
233 static void dump_replaygain(void *ctx
, AVPacketSideData
*sd
)
237 if (sd
->size
< sizeof(*rg
)) {
238 av_log(ctx
, AV_LOG_INFO
, "invalid data");
241 rg
= (AVReplayGain
*)sd
->data
;
243 print_gain(ctx
, "track gain", rg
->track_gain
);
244 print_peak(ctx
, "track peak", rg
->track_peak
);
245 print_gain(ctx
, "album gain", rg
->album_gain
);
246 print_peak(ctx
, "album peak", rg
->album_peak
);
249 static void dump_stereo3d(void *ctx
, AVPacketSideData
*sd
)
253 if (sd
->size
< sizeof(*stereo
)) {
254 av_log(ctx
, AV_LOG_INFO
, "invalid data");
258 stereo
= (AVStereo3D
*)sd
->data
;
260 switch (stereo
->type
) {
262 av_log(ctx
, AV_LOG_INFO
, "2D");
264 case AV_STEREO3D_SIDEBYSIDE
:
265 av_log(ctx
, AV_LOG_INFO
, "side by side");
267 case AV_STEREO3D_TOPBOTTOM
:
268 av_log(ctx
, AV_LOG_INFO
, "top and bottom");
270 case AV_STEREO3D_FRAMESEQUENCE
:
271 av_log(ctx
, AV_LOG_INFO
, "frame alternate");
273 case AV_STEREO3D_CHECKERBOARD
:
274 av_log(ctx
, AV_LOG_INFO
, "checkerboard");
276 case AV_STEREO3D_LINES
:
277 av_log(ctx
, AV_LOG_INFO
, "interleaved lines");
279 case AV_STEREO3D_COLUMNS
:
280 av_log(ctx
, AV_LOG_INFO
, "interleaved columns");
282 case AV_STEREO3D_SIDEBYSIDE_QUINCUNX
:
283 av_log(ctx
, AV_LOG_INFO
, "side by side (quincunx subsampling)");
286 av_log(ctx
, AV_LOG_WARNING
, "unknown");
290 if (stereo
->flags
& AV_STEREO3D_FLAG_INVERT
)
291 av_log(ctx
, AV_LOG_INFO
, " (inverted)");
294 static void dump_sidedata(void *ctx
, AVStream
*st
, const char *indent
)
298 if (st
->nb_side_data
)
299 av_log(ctx
, AV_LOG_INFO
, "%sSide data:\n", indent
);
301 for (i
= 0; i
< st
->nb_side_data
; i
++) {
302 AVPacketSideData sd
= st
->side_data
[i
];
303 av_log(ctx
, AV_LOG_INFO
, "%s ", indent
);
306 case AV_PKT_DATA_PALETTE
:
307 av_log(ctx
, AV_LOG_INFO
, "palette");
309 case AV_PKT_DATA_NEW_EXTRADATA
:
310 av_log(ctx
, AV_LOG_INFO
, "new extradata");
312 case AV_PKT_DATA_PARAM_CHANGE
:
313 av_log(ctx
, AV_LOG_INFO
, "paramchange: ");
314 dump_paramchange(ctx
, &sd
);
316 case AV_PKT_DATA_H263_MB_INFO
:
317 av_log(ctx
, AV_LOG_INFO
, "h263 macroblock info");
319 case AV_PKT_DATA_REPLAYGAIN
:
320 av_log(ctx
, AV_LOG_INFO
, "replaygain: ");
321 dump_replaygain(ctx
, &sd
);
323 case AV_PKT_DATA_DISPLAYMATRIX
:
324 av_log(ctx
, AV_LOG_INFO
, "displaymatrix: rotation of %.2f degrees",
325 av_display_rotation_get((int32_t *)sd
.data
));
327 case AV_PKT_DATA_STEREO3D
:
328 av_log(ctx
, AV_LOG_INFO
, "stereo3d: ");
329 dump_stereo3d(ctx
, &sd
);
332 av_log(ctx
, AV_LOG_WARNING
,
333 "unknown side data type %d (%d bytes)", sd
.type
, sd
.size
);
337 av_log(ctx
, AV_LOG_INFO
, "\n");
341 /* "user interface" functions */
342 static void dump_stream_format(AVFormatContext
*ic
, int i
,
343 int index
, int is_output
)
346 int flags
= (is_output
? ic
->oformat
->flags
: ic
->iformat
->flags
);
347 AVStream
*st
= ic
->streams
[i
];
348 AVDictionaryEntry
*lang
= av_dict_get(st
->metadata
, "language", NULL
, 0);
349 char *separator
= ic
->dump_separator
;
350 char **codec_separator
= av_opt_ptr(st
->codec
->av_class
, st
->codec
, "dump_separator");
351 int use_format_separator
= !*codec_separator
;
353 if (use_format_separator
)
354 *codec_separator
= av_strdup(separator
);
355 avcodec_string(buf
, sizeof(buf
), st
->codec
, is_output
);
356 if (use_format_separator
)
357 av_freep(codec_separator
);
358 av_log(NULL
, AV_LOG_INFO
, " Stream #%d:%d", index
, i
);
360 /* the pid is an important information, so we display it */
361 /* XXX: add a generic system */
362 if (flags
& AVFMT_SHOW_IDS
)
363 av_log(NULL
, AV_LOG_INFO
, "[0x%x]", st
->id
);
365 av_log(NULL
, AV_LOG_INFO
, "(%s)", lang
->value
);
366 av_log(NULL
, AV_LOG_DEBUG
, ", %d, %d/%d", st
->codec_info_nb_frames
,
367 st
->time_base
.num
, st
->time_base
.den
);
368 av_log(NULL
, AV_LOG_INFO
, ": %s", buf
);
370 if (st
->sample_aspect_ratio
.num
&& // default
371 av_cmp_q(st
->sample_aspect_ratio
, st
->codec
->sample_aspect_ratio
)) {
372 AVRational display_aspect_ratio
;
373 av_reduce(&display_aspect_ratio
.num
, &display_aspect_ratio
.den
,
374 st
->codec
->width
* st
->sample_aspect_ratio
.num
,
375 st
->codec
->height
* st
->sample_aspect_ratio
.den
,
377 av_log(NULL
, AV_LOG_INFO
, ", SAR %d:%d DAR %d:%d",
378 st
->sample_aspect_ratio
.num
, st
->sample_aspect_ratio
.den
,
379 display_aspect_ratio
.num
, display_aspect_ratio
.den
);
382 if (st
->codec
->codec_type
== AVMEDIA_TYPE_VIDEO
) {
383 int fps
= st
->avg_frame_rate
.den
&& st
->avg_frame_rate
.num
;
384 int tbr
= st
->r_frame_rate
.den
&& st
->r_frame_rate
.num
;
385 int tbn
= st
->time_base
.den
&& st
->time_base
.num
;
386 int tbc
= st
->codec
->time_base
.den
&& st
->codec
->time_base
.num
;
388 if (fps
|| tbr
|| tbn
|| tbc
)
389 av_log(NULL
, AV_LOG_INFO
, "%s", separator
);
392 print_fps(av_q2d(st
->avg_frame_rate
), tbr
|| tbn
|| tbc
? "fps, " : "fps");
394 print_fps(av_q2d(st
->r_frame_rate
), tbn
|| tbc
? "tbr, " : "tbr");
396 print_fps(1 / av_q2d(st
->time_base
), tbc
? "tbn, " : "tbn");
398 print_fps(1 / av_q2d(st
->codec
->time_base
), "tbc");
401 if (st
->disposition
& AV_DISPOSITION_DEFAULT
)
402 av_log(NULL
, AV_LOG_INFO
, " (default)");
403 if (st
->disposition
& AV_DISPOSITION_DUB
)
404 av_log(NULL
, AV_LOG_INFO
, " (dub)");
405 if (st
->disposition
& AV_DISPOSITION_ORIGINAL
)
406 av_log(NULL
, AV_LOG_INFO
, " (original)");
407 if (st
->disposition
& AV_DISPOSITION_COMMENT
)
408 av_log(NULL
, AV_LOG_INFO
, " (comment)");
409 if (st
->disposition
& AV_DISPOSITION_LYRICS
)
410 av_log(NULL
, AV_LOG_INFO
, " (lyrics)");
411 if (st
->disposition
& AV_DISPOSITION_KARAOKE
)
412 av_log(NULL
, AV_LOG_INFO
, " (karaoke)");
413 if (st
->disposition
& AV_DISPOSITION_FORCED
)
414 av_log(NULL
, AV_LOG_INFO
, " (forced)");
415 if (st
->disposition
& AV_DISPOSITION_HEARING_IMPAIRED
)
416 av_log(NULL
, AV_LOG_INFO
, " (hearing impaired)");
417 if (st
->disposition
& AV_DISPOSITION_VISUAL_IMPAIRED
)
418 av_log(NULL
, AV_LOG_INFO
, " (visual impaired)");
419 if (st
->disposition
& AV_DISPOSITION_CLEAN_EFFECTS
)
420 av_log(NULL
, AV_LOG_INFO
, " (clean effects)");
421 av_log(NULL
, AV_LOG_INFO
, "\n");
423 dump_metadata(NULL
, st
->metadata
, " ");
425 dump_sidedata(NULL
, st
, " ");
428 void av_dump_format(AVFormatContext
*ic
, int index
,
429 const char *url
, int is_output
)
432 uint8_t *printed
= ic
->nb_streams
? av_mallocz(ic
->nb_streams
) : NULL
;
433 if (ic
->nb_streams
&& !printed
)
436 av_log(NULL
, AV_LOG_INFO
, "%s #%d, %s, %s '%s':\n",
437 is_output
? "Output" : "Input",
439 is_output
? ic
->oformat
->name
: ic
->iformat
->name
,
440 is_output
? "to" : "from", url
);
441 dump_metadata(NULL
, ic
->metadata
, " ");
444 av_log(NULL
, AV_LOG_INFO
, " Duration: ");
445 if (ic
->duration
!= AV_NOPTS_VALUE
) {
446 int hours
, mins
, secs
, us
;
447 int64_t duration
= ic
->duration
+ 5000;
448 secs
= duration
/ AV_TIME_BASE
;
449 us
= duration
% AV_TIME_BASE
;
454 av_log(NULL
, AV_LOG_INFO
, "%02d:%02d:%02d.%02d", hours
, mins
, secs
,
455 (100 * us
) / AV_TIME_BASE
);
457 av_log(NULL
, AV_LOG_INFO
, "N/A");
459 if (ic
->start_time
!= AV_NOPTS_VALUE
) {
461 av_log(NULL
, AV_LOG_INFO
, ", start: ");
462 secs
= ic
->start_time
/ AV_TIME_BASE
;
463 us
= abs(ic
->start_time
% AV_TIME_BASE
);
464 av_log(NULL
, AV_LOG_INFO
, "%d.%06d",
465 secs
, (int) av_rescale(us
, 1000000, AV_TIME_BASE
));
467 av_log(NULL
, AV_LOG_INFO
, ", bitrate: ");
469 av_log(NULL
, AV_LOG_INFO
, "%d kb/s", ic
->bit_rate
/ 1000);
471 av_log(NULL
, AV_LOG_INFO
, "N/A");
472 av_log(NULL
, AV_LOG_INFO
, "\n");
475 for (i
= 0; i
< ic
->nb_chapters
; i
++) {
476 AVChapter
*ch
= ic
->chapters
[i
];
477 av_log(NULL
, AV_LOG_INFO
, " Chapter #%d:%d: ", index
, i
);
478 av_log(NULL
, AV_LOG_INFO
,
479 "start %f, ", ch
->start
* av_q2d(ch
->time_base
));
480 av_log(NULL
, AV_LOG_INFO
,
481 "end %f\n", ch
->end
* av_q2d(ch
->time_base
));
483 dump_metadata(NULL
, ch
->metadata
, " ");
486 if (ic
->nb_programs
) {
488 for (j
= 0; j
< ic
->nb_programs
; j
++) {
489 AVDictionaryEntry
*name
= av_dict_get(ic
->programs
[j
]->metadata
,
491 av_log(NULL
, AV_LOG_INFO
, " Program %d %s\n", ic
->programs
[j
]->id
,
492 name
? name
->value
: "");
493 dump_metadata(NULL
, ic
->programs
[j
]->metadata
, " ");
494 for (k
= 0; k
< ic
->programs
[j
]->nb_stream_indexes
; k
++) {
495 dump_stream_format(ic
, ic
->programs
[j
]->stream_index
[k
],
497 printed
[ic
->programs
[j
]->stream_index
[k
]] = 1;
499 total
+= ic
->programs
[j
]->nb_stream_indexes
;
501 if (total
< ic
->nb_streams
)
502 av_log(NULL
, AV_LOG_INFO
, " No Program\n");
505 for (i
= 0; i
< ic
->nb_streams
; i
++)
507 dump_stream_format(ic
, i
, index
, is_output
);