Liberally based on the work of Luca Barbato <lu_zero@gentoo.org>, done
for libav/avprobe.
... | ... |
@@ -2,6 +2,8 @@ Entries are sorted chronologically from oldest to youngest within each release, |
2 | 2 |
releases are sorted from youngest to oldest. |
3 | 3 |
|
4 | 4 |
version next: |
5 |
+- INI output in ffprobe |
|
6 |
+ |
|
5 | 7 |
|
6 | 8 |
version 0.11: |
7 | 9 |
Fixes:CVE-2012-2772, CVE-2012-2774, CVE-2012-2775, CVE-2012-2776, CVE-2012-2777, |
... | ... |
@@ -269,6 +269,45 @@ CSV format. |
269 | 269 |
This writer is equivalent to |
270 | 270 |
@code{compact=item_sep=,:nokey=1:escape=csv}. |
271 | 271 |
|
272 |
+@section ini |
|
273 |
+INI format output. |
|
274 |
+ |
|
275 |
+Print output in an INI based format. |
|
276 |
+ |
|
277 |
+The following conventions are adopted: |
|
278 |
+ |
|
279 |
+@itemize |
|
280 |
+@item |
|
281 |
+all key and values are UTF-8 |
|
282 |
+@item |
|
283 |
+'.' is the subgroup separator |
|
284 |
+@item |
|
285 |
+newline, '\t', '\f', '\b' and the following characters are escaped |
|
286 |
+@item |
|
287 |
+'\' is the escape character |
|
288 |
+@item |
|
289 |
+'#' is the comment indicator |
|
290 |
+@item |
|
291 |
+'=' is the key/value separator |
|
292 |
+@item |
|
293 |
+':' is not used but usually parsed as key/value separator |
|
294 |
+@end itemize |
|
295 |
+ |
|
296 |
+This writer accepts options as a list of @var{key}=@var{value} pairs, |
|
297 |
+separated by ":". |
|
298 |
+ |
|
299 |
+The description of the accepted options follows. |
|
300 |
+ |
|
301 |
+@table @option |
|
302 |
+@item hierarchical, h |
|
303 |
+Specify if the section name specification should be hierarchical. If |
|
304 |
+set to 1, and if there is more than one section in the current |
|
305 |
+chapter, the section name will be prefixed by the name of the |
|
306 |
+chapter. A value of 0 will disable this behavior. |
|
307 |
+ |
|
308 |
+Default value is 1. |
|
309 |
+@end table |
|
310 |
+ |
|
272 | 311 |
@section json |
273 | 312 |
JSON based format. |
274 | 313 |
|
... | ... |
@@ -713,6 +713,174 @@ static const Writer csv_writer = { |
713 | 713 |
.flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS, |
714 | 714 |
}; |
715 | 715 |
|
716 |
+/* INI format output */ |
|
717 |
+ |
|
718 |
+typedef struct { |
|
719 |
+ const AVClass *class; |
|
720 |
+ AVBPrint chapter_name, section_name; |
|
721 |
+ int print_packets_and_frames; |
|
722 |
+ int nb_frame; |
|
723 |
+ int nb_packet; |
|
724 |
+ int hierarchical; |
|
725 |
+} INIContext; |
|
726 |
+ |
|
727 |
+#undef OFFSET |
|
728 |
+#define OFFSET(x) offsetof(INIContext, x) |
|
729 |
+ |
|
730 |
+static const AVOption ini_options[] = { |
|
731 |
+ {"hierachical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.dbl=1}, 0, 1 }, |
|
732 |
+ {"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_INT, {.dbl=1}, 0, 1 }, |
|
733 |
+ {NULL}, |
|
734 |
+}; |
|
735 |
+ |
|
736 |
+static const char *ini_get_name(void *ctx) |
|
737 |
+{ |
|
738 |
+ return "ini"; |
|
739 |
+} |
|
740 |
+ |
|
741 |
+static const AVClass ini_class = { |
|
742 |
+ "INIContext", |
|
743 |
+ ini_get_name, |
|
744 |
+ ini_options |
|
745 |
+}; |
|
746 |
+ |
|
747 |
+static av_cold int ini_init(WriterContext *wctx, const char *args, void *opaque) |
|
748 |
+{ |
|
749 |
+ INIContext *ini = wctx->priv; |
|
750 |
+ int err; |
|
751 |
+ |
|
752 |
+ av_bprint_init(&ini->chapter_name, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
753 |
+ av_bprint_init(&ini->section_name, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
754 |
+ ini->nb_frame = ini->nb_packet = 0; |
|
755 |
+ |
|
756 |
+ ini->class = &ini_class; |
|
757 |
+ av_opt_set_defaults(ini); |
|
758 |
+ |
|
759 |
+ if (args && (err = av_set_options_string(ini, args, "=", ":")) < 0) { |
|
760 |
+ av_log(wctx, AV_LOG_ERROR, "Error parsing options string: '%s'\n", args); |
|
761 |
+ return err; |
|
762 |
+ } |
|
763 |
+ |
|
764 |
+ return 0; |
|
765 |
+} |
|
766 |
+ |
|
767 |
+static av_cold void ini_uninit(WriterContext *wctx) |
|
768 |
+{ |
|
769 |
+ INIContext *ini = wctx->priv; |
|
770 |
+ av_bprint_finalize(&ini->chapter_name, NULL); |
|
771 |
+ av_bprint_finalize(&ini->section_name, NULL); |
|
772 |
+} |
|
773 |
+ |
|
774 |
+static void ini_print_header(WriterContext *wctx) |
|
775 |
+{ |
|
776 |
+ printf("# ffprobe output\n\n"); |
|
777 |
+} |
|
778 |
+ |
|
779 |
+static char *ini_escape_str(AVBPrint *dst, const char *src) |
|
780 |
+{ |
|
781 |
+ int i = 0; |
|
782 |
+ char c = 0; |
|
783 |
+ |
|
784 |
+ while (c = src[i++]) { |
|
785 |
+ switch (c) { |
|
786 |
+ case '\b': av_bprintf(dst, "%s", "\\b"); break; |
|
787 |
+ case '\f': av_bprintf(dst, "%s", "\\f"); break; |
|
788 |
+ case '\n': av_bprintf(dst, "%s", "\\n"); break; |
|
789 |
+ case '\r': av_bprintf(dst, "%s", "\\r"); break; |
|
790 |
+ case '\t': av_bprintf(dst, "%s", "\\t"); break; |
|
791 |
+ case '\\': |
|
792 |
+ case '#' : |
|
793 |
+ case '=' : |
|
794 |
+ case ':' : av_bprint_chars(dst, '\\', 1); |
|
795 |
+ default: |
|
796 |
+ if ((unsigned char)c < 32) |
|
797 |
+ av_bprintf(dst, "\\x00%02x", c & 0xff); |
|
798 |
+ else |
|
799 |
+ av_bprint_chars(dst, c, 1); |
|
800 |
+ break; |
|
801 |
+ } |
|
802 |
+ } |
|
803 |
+ return dst->str; |
|
804 |
+} |
|
805 |
+ |
|
806 |
+static void ini_print_chapter_header(WriterContext *wctx, const char *chapter) |
|
807 |
+{ |
|
808 |
+ INIContext *ini = wctx->priv; |
|
809 |
+ |
|
810 |
+ av_bprint_clear(&ini->chapter_name); |
|
811 |
+ av_bprintf(&ini->chapter_name, "%s", chapter); |
|
812 |
+ |
|
813 |
+ if (wctx->nb_chapter) |
|
814 |
+ printf("\n"); |
|
815 |
+ ini->print_packets_and_frames = !strcmp("packets_and_frames", chapter); |
|
816 |
+} |
|
817 |
+ |
|
818 |
+static void ini_print_section_header(WriterContext *wctx, const char *section) |
|
819 |
+{ |
|
820 |
+ INIContext *ini = wctx->priv; |
|
821 |
+ int n; |
|
822 |
+ if (wctx->nb_section) |
|
823 |
+ printf("\n"); |
|
824 |
+ av_bprint_clear(&ini->section_name); |
|
825 |
+ |
|
826 |
+ if (ini->hierarchical && wctx->multiple_sections) |
|
827 |
+ av_bprintf(&ini->section_name, "%s.", ini->chapter_name.str); |
|
828 |
+ av_bprintf(&ini->section_name, "%s", section); |
|
829 |
+ |
|
830 |
+ if (ini->print_packets_and_frames) |
|
831 |
+ n = !strcmp(section, "packet") ? ini->nb_packet++ : ini->nb_frame++; |
|
832 |
+ else |
|
833 |
+ n = wctx->nb_section; |
|
834 |
+ if (wctx->multiple_sections) |
|
835 |
+ av_bprintf(&ini->section_name, ".%d", n); |
|
836 |
+ printf("[%s]\n", ini->section_name.str); |
|
837 |
+} |
|
838 |
+ |
|
839 |
+static void ini_print_str(WriterContext *wctx, const char *key, const char *value) |
|
840 |
+{ |
|
841 |
+ AVBPrint buf; |
|
842 |
+ |
|
843 |
+ av_bprint_init(&buf, 1, AV_BPRINT_SIZE_UNLIMITED); |
|
844 |
+ printf("%s=", ini_escape_str(&buf, key)); |
|
845 |
+ av_bprint_clear(&buf); |
|
846 |
+ printf("%s\n", ini_escape_str(&buf, value)); |
|
847 |
+ av_bprint_finalize(&buf, NULL); |
|
848 |
+} |
|
849 |
+ |
|
850 |
+static void ini_print_int(WriterContext *wctx, const char *key, long long int value) |
|
851 |
+{ |
|
852 |
+ printf("%s=%lld\n", key, value); |
|
853 |
+} |
|
854 |
+ |
|
855 |
+static void ini_show_tags(WriterContext *wctx, AVDictionary *dict) |
|
856 |
+{ |
|
857 |
+ INIContext *ini = wctx->priv; |
|
858 |
+ AVDictionaryEntry *tag = NULL; |
|
859 |
+ int is_first = 1; |
|
860 |
+ |
|
861 |
+ while ((tag = av_dict_get(dict, "", tag, AV_DICT_IGNORE_SUFFIX))) { |
|
862 |
+ if (is_first) { |
|
863 |
+ printf("\n[%s.tags]\n", ini->section_name.str); |
|
864 |
+ is_first = 0; |
|
865 |
+ } |
|
866 |
+ writer_print_string(wctx, tag->key, tag->value, 0); |
|
867 |
+ } |
|
868 |
+} |
|
869 |
+ |
|
870 |
+static const Writer ini_writer = { |
|
871 |
+ .name = "ini", |
|
872 |
+ .priv_size = sizeof(INIContext), |
|
873 |
+ .init = ini_init, |
|
874 |
+ .uninit = ini_uninit, |
|
875 |
+ .print_header = ini_print_header, |
|
876 |
+ .print_chapter_header = ini_print_chapter_header, |
|
877 |
+ .print_section_header = ini_print_section_header, |
|
878 |
+ .print_integer = ini_print_int, |
|
879 |
+ .print_string = ini_print_str, |
|
880 |
+ .show_tags = ini_show_tags, |
|
881 |
+ .flags = WRITER_FLAG_DISPLAY_OPTIONAL_FIELDS|WRITER_FLAG_PUT_PACKETS_AND_FRAMES_IN_SAME_CHAPTER, |
|
882 |
+}; |
|
883 |
+ |
|
716 | 884 |
/* JSON output */ |
717 | 885 |
|
718 | 886 |
typedef struct { |
... | ... |
@@ -1168,6 +1336,7 @@ static void writer_register_all(void) |
1168 | 1168 |
writer_register(&default_writer); |
1169 | 1169 |
writer_register(&compact_writer); |
1170 | 1170 |
writer_register(&csv_writer); |
1171 |
+ writer_register(&ini_writer); |
|
1171 | 1172 |
writer_register(&json_writer); |
1172 | 1173 |
writer_register(&xml_writer); |
1173 | 1174 |
} |
... | ... |
@@ -1734,7 +1903,7 @@ static const OptionDef options[] = { |
1734 | 1734 |
{ "pretty", 0, {(void*)&opt_pretty}, |
1735 | 1735 |
"prettify the format of displayed values, make it more human readable" }, |
1736 | 1736 |
{ "print_format", OPT_STRING | HAS_ARG, {(void*)&print_format}, |
1737 |
- "set the output printing format (available formats are: default, compact, csv, json, xml)", "format" }, |
|
1737 |
+ "set the output printing format (available formats are: default, compact, csv, ini, json, xml)", "format" }, |
|
1738 | 1738 |
{ "show_error", OPT_BOOL, {(void*)&do_show_error} , "show probing error" }, |
1739 | 1739 |
{ "show_format", OPT_BOOL, {(void*)&do_show_format} , "show format/container info" }, |
1740 | 1740 |
{ "show_frames", OPT_BOOL, {(void*)&do_show_frames} , "show frames info" }, |