diff --git a/doc/ffprobe.texi b/doc/ffprobe.texi index 2e9bfee29a..75d1e72ca8 100644 --- a/doc/ffprobe.texi +++ b/doc/ffprobe.texi @@ -197,11 +197,11 @@ The information for each single packet is printed within a dedicated section with name "PACKET". @item -show_frames -Show information about each frame contained in the input multimedia -stream. +Show information about each frame and subtitle contained in the input +multimedia stream. The information for each single frame is printed within a dedicated -section with name "FRAME". +section with name "FRAME" or "SUBTITLE". @item -show_streams Show information about each media stream contained in the input diff --git a/doc/ffprobe.xsd b/doc/ffprobe.xsd index 6a48ff432b..cc3d1b63f7 100644 --- a/doc/ffprobe.xsd +++ b/doc/ffprobe.xsd @@ -28,7 +28,10 @@ - + + + + @@ -82,6 +85,16 @@ + + + + + + + + + + diff --git a/ffprobe.c b/ffprobe.c index 3b6c173523..1842452195 100644 --- a/ffprobe.c +++ b/ffprobe.c @@ -135,6 +135,7 @@ typedef enum { SECTION_ID_STREAM_DISPOSITION, SECTION_ID_STREAMS, SECTION_ID_STREAM_TAGS, + SECTION_ID_SUBTITLE, } SectionID; static struct section sections[] = { @@ -144,7 +145,7 @@ static struct section sections[] = { [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" }, - [SECTION_ID_FRAMES] = { SECTION_ID_FRAMES, "frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME, -1 } }, + [SECTION_ID_FRAMES] = { SECTION_ID_FRAMES, "frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME, SECTION_ID_SUBTITLE, -1 } }, [SECTION_ID_FRAME] = { SECTION_ID_FRAME, "frame", 0, { SECTION_ID_FRAME_TAGS, -1 } }, [SECTION_ID_FRAME_TAGS] = { SECTION_ID_FRAME_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "frame_tags" }, [SECTION_ID_LIBRARY_VERSIONS] = { SECTION_ID_LIBRARY_VERSIONS, "library_versions", SECTION_FLAG_IS_ARRAY, { SECTION_ID_LIBRARY_VERSION, -1 } }, @@ -167,6 +168,7 @@ static struct section sections[] = { [SECTION_ID_STREAM] = { SECTION_ID_STREAM, "stream", 0, { SECTION_ID_STREAM_DISPOSITION, SECTION_ID_STREAM_TAGS, -1 } }, [SECTION_ID_STREAM_DISPOSITION] = { SECTION_ID_STREAM_DISPOSITION, "disposition", 0, { -1 }, .unique_name = "stream_disposition" }, [SECTION_ID_STREAM_TAGS] = { SECTION_ID_STREAM_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "stream_tags" }, + [SECTION_ID_SUBTITLE] = { SECTION_ID_SUBTITLE, "subtitle", 0, { -1 } }, }; static const OptionDef *options; @@ -1675,6 +1677,29 @@ static void show_packet(WriterContext *w, AVFormatContext *fmt_ctx, AVPacket *pk fflush(stdout); } +static void show_subtitle(WriterContext *w, AVSubtitle *sub, AVStream *stream, + AVFormatContext *fmt_ctx) +{ + AVBPrint pbuf; + + av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED); + + writer_print_section_header(w, SECTION_ID_SUBTITLE); + + print_str ("media_type", "subtitle"); + print_ts ("pts", sub->pts); + print_time("pts_time", sub->pts, &AV_TIME_BASE_Q); + print_int ("format", sub->format); + print_int ("start_display_time", sub->start_display_time); + print_int ("end_display_time", sub->end_display_time); + print_int ("num_rects", sub->num_rects); + + writer_print_section_footer(w); + + av_bprint_finalize(&pbuf, NULL); + fflush(stdout); +} + static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream, AVFormatContext *fmt_ctx) { @@ -1751,6 +1776,7 @@ static av_always_inline int process_frame(WriterContext *w, AVFrame *frame, AVPacket *pkt) { AVCodecContext *dec_ctx = fmt_ctx->streams[pkt->stream_index]->codec; + AVSubtitle sub; int ret = 0, got_frame = 0; avcodec_get_frame_defaults(frame); @@ -1763,6 +1789,10 @@ static av_always_inline int process_frame(WriterContext *w, case AVMEDIA_TYPE_AUDIO: ret = avcodec_decode_audio4(dec_ctx, frame, &got_frame, pkt); break; + + case AVMEDIA_TYPE_SUBTITLE: + ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_frame, pkt); + break; } } @@ -1772,9 +1802,15 @@ static av_always_inline int process_frame(WriterContext *w, pkt->data += ret; pkt->size -= ret; if (got_frame) { + int is_sub = (dec_ctx->codec_type == AVMEDIA_TYPE_SUBTITLE); nb_streams_frames[pkt->stream_index]++; if (do_show_frames) - show_frame(w, frame, fmt_ctx->streams[pkt->stream_index], fmt_ctx); + if (is_sub) + show_subtitle(w, &sub, fmt_ctx->streams[pkt->stream_index], fmt_ctx); + else + show_frame(w, frame, fmt_ctx->streams[pkt->stream_index], fmt_ctx); + if (is_sub) + avsubtitle_free(&sub); } return got_frame; }