mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
ffprobe: show chapter and chapter metadata information
Address trac ticket #2636.
This commit is contained in:
parent
21d0f75f29
commit
4da5402256
@ -64,6 +64,7 @@ version <next>:
|
||||
- Go2Webinar decoder
|
||||
- mcdeint filter ported from libmpcodecs
|
||||
- sab filter ported from libmpcodecs
|
||||
- ffprobe -show_chapters option
|
||||
|
||||
|
||||
version 1.2:
|
||||
|
@ -209,6 +209,11 @@ multimedia stream.
|
||||
Each media stream information is printed within a dedicated section
|
||||
with name "STREAM".
|
||||
|
||||
@item -show_chapters
|
||||
Show information about chapters stored in the format.
|
||||
|
||||
Each chapter is printed within a dedicated section with name "CHAPTER".
|
||||
|
||||
@item -count_frames
|
||||
Count the number of frames per stream and report it in the
|
||||
corresponding stream section.
|
||||
|
@ -11,6 +11,7 @@
|
||||
<xsd:element name="packets" type="ffprobe:packetsType" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="frames" type="ffprobe:framesType" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="streams" type="ffprobe:streamsType" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="chapters" type="ffprobe:chaptersType" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="format" type="ffprobe:formatType" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="error" type="ffprobe:errorType" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="program_version" type="ffprobe:programVersionType" minOccurs="0" maxOccurs="1" />
|
||||
@ -181,6 +182,25 @@
|
||||
<xsd:attribute name="configuration" type="xsd:string" use="required"/>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="chaptersType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="chapter" type="ffprobe:chapterType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="chapterType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="tag" type="ffprobe:tagType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
|
||||
<xsd:attribute name="id" type="xsd:int" use="required"/>
|
||||
<xsd:attribute name="time_base" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="start" type="xsd:int" use="required"/>
|
||||
<xsd:attribute name="start_time" type="xsd:float"/>
|
||||
<xsd:attribute name="end" type="xsd:int" use="required"/>
|
||||
<xsd:attribute name="end_time" type="xsd:float" use="required"/>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="libraryVersionType">
|
||||
<xsd:attribute name="name" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="major" type="xsd:int" use="required"/>
|
||||
|
37
ffprobe.c
37
ffprobe.c
@ -52,6 +52,7 @@ static int do_count_frames = 0;
|
||||
static int do_count_packets = 0;
|
||||
static int do_read_frames = 0;
|
||||
static int do_read_packets = 0;
|
||||
static int do_show_chapters = 0;
|
||||
static int do_show_error = 0;
|
||||
static int do_show_format = 0;
|
||||
static int do_show_frames = 0;
|
||||
@ -93,6 +94,9 @@ struct section {
|
||||
|
||||
typedef enum {
|
||||
SECTION_ID_NONE = -1,
|
||||
SECTION_ID_CHAPTER,
|
||||
SECTION_ID_CHAPTER_TAGS,
|
||||
SECTION_ID_CHAPTERS,
|
||||
SECTION_ID_ERROR,
|
||||
SECTION_ID_FORMAT,
|
||||
SECTION_ID_FORMAT_TAGS,
|
||||
@ -113,6 +117,9 @@ typedef enum {
|
||||
} SectionID;
|
||||
|
||||
static struct section sections[] = {
|
||||
[SECTION_ID_CHAPTERS] = { SECTION_ID_CHAPTERS, "chapters", SECTION_FLAG_IS_ARRAY, { SECTION_ID_CHAPTER, -1 } },
|
||||
[SECTION_ID_CHAPTER] = { SECTION_ID_CHAPTER, "chapter", 0, { SECTION_ID_CHAPTER_TAGS, -1 } },
|
||||
[SECTION_ID_CHAPTER_TAGS] = { SECTION_ID_CHAPTER_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "chapter_tags" },
|
||||
[SECTION_ID_ERROR] = { SECTION_ID_ERROR, "error", 0, { -1 } },
|
||||
[SECTION_ID_FORMAT] = { SECTION_ID_FORMAT, "format", 0, { SECTION_ID_FORMAT_TAGS, -1 } },
|
||||
[SECTION_ID_FORMAT_TAGS] = { SECTION_ID_FORMAT_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "format_tags" },
|
||||
@ -126,7 +133,7 @@ static struct section sections[] = {
|
||||
[SECTION_ID_PACKET] = { SECTION_ID_PACKET, "packet", 0, { -1 } },
|
||||
[SECTION_ID_PROGRAM_VERSION] = { SECTION_ID_PROGRAM_VERSION, "program_version", 0, { -1 } },
|
||||
[SECTION_ID_ROOT] = { SECTION_ID_ROOT, "root", SECTION_FLAG_IS_WRAPPER,
|
||||
{ SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_STREAMS, SECTION_ID_PACKETS,
|
||||
{ SECTION_ID_CHAPTERS, SECTION_ID_FORMAT, SECTION_ID_FRAMES, SECTION_ID_STREAMS, SECTION_ID_PACKETS,
|
||||
SECTION_ID_ERROR, SECTION_ID_PROGRAM_VERSION, SECTION_ID_LIBRARY_VERSIONS, -1} },
|
||||
[SECTION_ID_STREAMS] = { SECTION_ID_STREAMS, "streams", SECTION_FLAG_IS_ARRAY, { SECTION_ID_STREAM, -1 } },
|
||||
[SECTION_ID_STREAM] = { SECTION_ID_STREAM, "stream", 0, { SECTION_ID_STREAM_DISPOSITION, SECTION_ID_STREAM_TAGS, -1 } },
|
||||
@ -1751,6 +1758,27 @@ static void show_streams(WriterContext *w, AVFormatContext *fmt_ctx)
|
||||
writer_print_section_footer(w);
|
||||
}
|
||||
|
||||
static void show_chapters(WriterContext *w, AVFormatContext *fmt_ctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
writer_print_section_header(w, SECTION_ID_CHAPTERS);
|
||||
for (i = 0; i < fmt_ctx->nb_chapters; i++) {
|
||||
AVChapter *chapter = fmt_ctx->chapters[i];
|
||||
|
||||
writer_print_section_header(w, SECTION_ID_CHAPTER);
|
||||
print_int("id", chapter->id);
|
||||
print_q ("time_base", chapter->time_base, '/');
|
||||
print_int("start", chapter->start);
|
||||
print_time("start_time", chapter->start, &chapter->time_base);
|
||||
print_int("end", chapter->end);
|
||||
print_time("end_time", chapter->end, &chapter->time_base);
|
||||
show_tags(w, chapter->metadata, SECTION_ID_CHAPTER_TAGS);
|
||||
writer_print_section_footer(w);
|
||||
}
|
||||
writer_print_section_footer(w);
|
||||
}
|
||||
|
||||
static void show_format(WriterContext *w, AVFormatContext *fmt_ctx)
|
||||
{
|
||||
char val_str[128];
|
||||
@ -1911,6 +1939,8 @@ static int probe_file(WriterContext *wctx, const char *filename)
|
||||
}
|
||||
if (do_show_streams)
|
||||
show_streams(wctx, fmt_ctx);
|
||||
if (do_show_chapters)
|
||||
show_chapters(wctx, fmt_ctx);
|
||||
if (do_show_format)
|
||||
show_format(wctx, fmt_ctx);
|
||||
|
||||
@ -2165,6 +2195,7 @@ static int opt_show_versions(const char *opt, const char *arg)
|
||||
return 0; \
|
||||
}
|
||||
|
||||
DEFINE_OPT_SHOW_SECTION(chapters, CHAPTERS);
|
||||
DEFINE_OPT_SHOW_SECTION(error, ERROR);
|
||||
DEFINE_OPT_SHOW_SECTION(format, FORMAT);
|
||||
DEFINE_OPT_SHOW_SECTION(frames, FRAMES);
|
||||
@ -2199,6 +2230,7 @@ static const OptionDef real_options[] = {
|
||||
"show a set of specified entries", "entry_list" },
|
||||
{ "show_packets", 0, {(void*)&opt_show_packets}, "show packets info" },
|
||||
{ "show_streams", 0, {(void*)&opt_show_streams}, "show streams info" },
|
||||
{ "show_chapters", 0, {(void*)&opt_show_chapters}, "show chapters info" },
|
||||
{ "count_frames", OPT_BOOL, {(void*)&do_count_frames}, "count the number of frames per stream" },
|
||||
{ "count_packets", OPT_BOOL, {(void*)&do_count_packets}, "count the number of packets per stream" },
|
||||
{ "show_program_version", 0, {(void*)&opt_show_program_version}, "show ffprobe version" },
|
||||
@ -2253,6 +2285,7 @@ int main(int argc, char **argv)
|
||||
parse_options(NULL, argc, argv, options, opt_input_file);
|
||||
|
||||
/* mark things to show, based on -show_entries */
|
||||
SET_DO_SHOW(CHAPTERS, chapters);
|
||||
SET_DO_SHOW(ERROR, error);
|
||||
SET_DO_SHOW(FORMAT, format);
|
||||
SET_DO_SHOW(FRAMES, frames);
|
||||
@ -2298,7 +2331,7 @@ int main(int argc, char **argv)
|
||||
ffprobe_show_library_versions(wctx);
|
||||
|
||||
if (!input_filename &&
|
||||
((do_show_format || do_show_streams || do_show_packets || do_show_error) ||
|
||||
((do_show_format || do_show_streams || do_show_chapters || do_show_packets || do_show_error) ||
|
||||
(!do_show_program_version && !do_show_library_versions))) {
|
||||
show_usage();
|
||||
av_log(NULL, AV_LOG_ERROR, "You have to specify one input file.\n");
|
||||
|
Loading…
Reference in New Issue
Block a user