[FFmpeg-devel] [PATCHv2] ffprobe: add support for subtitle frames

Stefano Sabatini stefasab at gmail.com
Sun Nov 24 21:55:42 CET 2013


On date Sunday 2013-11-24 15:09:52 +0100, Marton Balint encoded:
> Signed-off-by: Marton Balint <cus at passwd.hu>
> ---
>  doc/ffprobe.texi |  6 +++---
>  doc/ffprobe.xsd  | 15 ++++++++++++++-
>  ffprobe.c        | 41 +++++++++++++++++++++++++++++++++++++++--
>  3 files changed, 56 insertions(+), 6 deletions(-)
> 
> diff --git a/doc/ffprobe.texi b/doc/ffprobe.texi
> index 2e9bfee..75d1e72 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 6a48ff4..cc3d1b6 100644
> --- a/doc/ffprobe.xsd
> +++ b/doc/ffprobe.xsd
> @@ -28,7 +28,10 @@
>  
>      <xsd:complexType name="framesType">
>          <xsd:sequence>
> -            <xsd:element name="frame" type="ffprobe:frameType" minOccurs="0" maxOccurs="unbounded"/>
> +            <xsd:choice minOccurs="0" maxOccurs="unbounded">
> +                <xsd:element name="frame" type="ffprobe:frameType" minOccurs="0" maxOccurs="unbounded"/>
> +                <xsd:element name="subtitle" type="ffprobe:subtitleType" minOccurs="0" maxOccurs="unbounded"/>
> +            </xsd:choice>
>          </xsd:sequence>
>      </xsd:complexType>
>  
> @@ -82,6 +85,16 @@
>        <xsd:attribute name="repeat_pict"            type="xsd:int"   />
>      </xsd:complexType>
>  
> +    <xsd:complexType name="subtitleType">
> +      <xsd:attribute name="media_type"         type="xsd:string" fixed="subtitle" use="required"/>
> +      <xsd:attribute name="pts"                type="xsd:long" />
> +      <xsd:attribute name="pts_time"           type="xsd:float"/>
> +      <xsd:attribute name="format"             type="xsd:int"  />
> +      <xsd:attribute name="start_display_time" type="xsd:int"  />
> +      <xsd:attribute name="end_display_time"   type="xsd:int"  />
> +      <xsd:attribute name="num_rects"          type="xsd:int"  />
> +    </xsd:complexType>
> +
>      <xsd:complexType name="streamsType">
>          <xsd:sequence>
>              <xsd:element name="stream" type="ffprobe:streamType" minOccurs="0" maxOccurs="unbounded"/>
> diff --git a/ffprobe.c b/ffprobe.c
> index ef4ccaf..75c3c5d 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;
> @@ -1676,6 +1678,30 @@ 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)

nit++: weird indent

> +{
> +    AVBPrint pbuf;
> +    AVRational tb = (AVRational){1, AV_TIME_BASE};
> +
> +    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, &tb);

&AV_TIME_BASE_Q should also work

> +    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)
>  {
> @@ -1752,6 +1778,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);
> @@ -1764,6 +1791,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;
>          }
>      }
>  
> @@ -1773,9 +1804,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);

Looks good otherwise, thanks. I'll push with the fixes if there are no
more comments.
-- 
FFmpeg = Fanciful & Fundamentalist Majestic Power Encoding/decoding Geisha


More information about the ffmpeg-devel mailing list