diff mbox series

[FFmpeg-devel,v5,02/12] global: Merge AVSubtitle into AVFrame

Message ID MN2PR04MB598142C58B2CE76387A0078BBAD89@MN2PR04MB5981.namprd04.prod.outlook.com
State New
Headers show
Series [FFmpeg-devel,v5,01/12] avutil/frame: Subtitle Filtering - Add AVMediaType property to AVFrame
Related show

Commit Message

Soft Works Sept. 12, 2021, 3:21 a.m. UTC
Signed-off-by: softworkz <softworkz@hotmail.com>
---
 libavcodec/ass.c                 |  16 ++--
 libavcodec/ass.h                 |   8 +-
 libavcodec/assdec.c              |  18 ++---
 libavcodec/assenc.c              |  10 +--
 libavcodec/avcodec.c             |  19 -----
 libavcodec/avcodec.h             |  81 ++++----------------
 libavcodec/ccaption_dec.c        |  28 +++----
 libavcodec/codec.h               |   4 +-
 libavcodec/codec_desc.h          |   4 +-
 libavcodec/decode.c              |  23 +++---
 libavcodec/dvbsubdec.c           |  48 ++++++------
 libavcodec/dvbsubenc.c           |  72 +++++++++---------
 libavcodec/dvdsubdec.c           | 122 +++++++++++++++----------------
 libavcodec/dvdsubenc.c           |  40 +++++-----
 libavcodec/encode.c              |   6 +-
 libavcodec/jacosubdec.c          |   4 +-
 libavcodec/libzvbi-teletextdec.c |  16 ++--
 libavcodec/microdvddec.c         |   4 +-
 libavcodec/movtextdec.c          |   4 +-
 libavcodec/movtextenc.c          |  10 +--
 libavcodec/mpl2dec.c             |   4 +-
 libavcodec/pgssubdec.c           |  68 ++++++++---------
 libavcodec/realtextdec.c         |   4 +-
 libavcodec/samidec.c             |   4 +-
 libavcodec/srtdec.c              |   4 +-
 libavcodec/srtenc.c              |  14 ++--
 libavcodec/subviewerdec.c        |   4 +-
 libavcodec/textdec.c             |   4 +-
 libavcodec/ttmlenc.c             |  10 +--
 libavcodec/utils.c               |  11 +++
 libavcodec/webvttdec.c           |   4 +-
 libavcodec/webvttenc.c           |  10 +--
 libavcodec/xsubdec.c             |  58 +++++++--------
 libavcodec/xsubenc.c             |  48 ++++++------
 libavfilter/vf_subtitles.c       |  28 +++----
 libavformat/utils.c              |   5 +-
 libavutil/Makefile               |   2 +
 libavutil/frame.c                |  41 ++++++++++-
 libavutil/frame.h                |  12 +++
 libavutil/subfmt.c               |  52 +++++++++++++
 libavutil/subfmt.h               |  94 ++++++++++++++++++++++++
 41 files changed, 576 insertions(+), 442 deletions(-)
 create mode 100644 libavutil/subfmt.c
 create mode 100644 libavutil/subfmt.h

Comments

Andreas Rheinhardt Sept. 12, 2021, 10:05 p.m. UTC | #1
Soft Works:
> Signed-off-by: softworkz <softworkz@hotmail.com>
> ---

> diff --git a/libavutil/frame.c b/libavutil/frame.c
> index ef2867d318..1855de9b3d 100644
> --- a/libavutil/frame.c
> +++ b/libavutil/frame.c
> @@ -72,7 +72,12 @@ static void get_frame_defaults(AVFrame *frame)
>      frame->colorspace          = AVCOL_SPC_UNSPECIFIED;
>      frame->color_range         = AVCOL_RANGE_UNSPECIFIED;
>      frame->chroma_location     = AVCHROMA_LOC_UNSPECIFIED;
> -    frame->flags               = 0;
> +    frame->subtitle_start_time = 0;
> +    frame->subtitle_end_time   = 0;
> +    frame->num_subtitle_rects  = 0;
> +    frame->subtitle_rects      = NULL;
> +    frame->subtitle_pts        = 0;
> +    frame->subtitle_header     = NULL;
>  }
>  
>  static void free_side_data(AVFrameSideData **ptr_sd)
> @@ -306,6 +311,9 @@ static int frame_copy_props(AVFrame *dst, const AVFrame *src, int force_copy)
>      dst->colorspace             = src->colorspace;
>      dst->color_range            = src->color_range;
>      dst->chroma_location        = src->chroma_location;
> +    dst->subtitle_start_time    = src->subtitle_start_time;
> +    dst->subtitle_end_time      = src->subtitle_end_time;
> +    dst->subtitle_pts           = src->subtitle_pts;
>  
>      av_dict_copy(&dst->metadata, src->metadata, 0);
>  
> @@ -359,6 +367,19 @@ int av_frame_ref(AVFrame *dst, const AVFrame *src)
>      if (ret < 0)
>          goto fail;
>  
> +    /* duplicate subtitle rects */
> +    dst->num_subtitle_rects = src->num_subtitle_rects;
> +
> +    if (src->num_subtitle_rects) {
> +        dst->subtitle_rects = av_malloc_array(src->num_subtitle_rects, sizeof(AVSubtitleRect *));
> +
> +        for (i = 0; i < src->num_subtitle_rects; i++) {
> +            AVSubtitleRect *rect = src->subtitle_rects[i];
> +            rect->nb_refs++;
> +            dst->subtitle_rects[i] = rect;
> +        }
> +    }
> +
>      /* duplicate the frame data if it's not refcounted */
>      if (!src->buf[0]) {
>          ret = av_frame_get_buffer2(dst, 0);
> @@ -472,6 +493,24 @@ void av_frame_unref(AVFrame *frame)
>      av_buffer_unref(&frame->opaque_ref);
>      av_buffer_unref(&frame->private_ref);
>  
> +    for (i = 0; i < frame->num_subtitle_rects; i++) {
> +        AVSubtitleRect *rect = frame->subtitle_rects[i];
> +
> +        if (rect && rect->nb_refs > 0)
> +            rect->nb_refs--;
> +        else {
> +            av_freep(&rect->data[0]);
> +            av_freep(&rect->data[1]);
> +            av_freep(&rect->data[2]);
> +            av_freep(&rect->data[3]);
> +            av_freep(&rect->text);
> +            av_freep(&rect->ass);
> +            av_freep(&rect);

This should better be av_freep(&frame->subtitle_rects[i]);

> +        }
> +    }
> +
> +    av_freep(&frame->subtitle_rects);
> +
>      get_frame_defaults(frame);
>  }
>  
> diff --git a/libavutil/frame.h b/libavutil/frame.h
> index 005eed9d18..4e2cfe19b3 100644
> --- a/libavutil/frame.h
> +++ b/libavutil/frame.h
> @@ -34,6 +34,7 @@
>  #include "rational.h"
>  #include "samplefmt.h"
>  #include "pixfmt.h"
> +#include "subfmt.h"
>  #include "version.h"
>  
>  
> @@ -469,6 +470,17 @@ typedef struct AVFrame {
>       */
>      uint64_t channel_layout;
>  
> +    uint32_t subtitle_start_time; /* display start time, relative to packet pts, in ms */
> +    uint32_t subtitle_end_time; /* display end time, relative to packet pts, in ms */
> +    unsigned num_subtitle_rects;
> +    AVSubtitleRect **subtitle_rects;
> +    int64_t subtitle_pts;    ///< Same as packet pts, in AV_TIME_BASE
> +
> +    /**
> +     * Header containing style information for text subtitles.
> +     */
> +    char *subtitle_header;
> +
>      /**
>       * AVBuffer references backing the data for this frame. If all elements of
>       * this array are NULL, then this frame is not reference counted. This array
> diff --git a/libavutil/subfmt.c b/libavutil/subfmt.c
> new file mode 100644
> index 0000000000..9a19d01aa3
> --- /dev/null
> +++ b/libavutil/subfmt.c
> @@ -0,0 +1,52 @@
> +/*
> + * Copyright (c) 2021 softworkz
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include <string.h>
> +#include "common.h"
> +#include "subfmt.h"
> +
> +typedef struct SubtitleFmtInfo {
> +    enum AVSubtitleType fmt;
> +    char* name;
> +} SubtitleFmtInfo;
> +
> +static SubtitleFmtInfo sub_fmt_info[AV_SUBTITLE_FMT_NB] = {
> +    {.fmt = AV_SUBTITLE_FMT_UNKNOWN, .name = "Unknown subtitle format", },
> +    {.fmt = AV_SUBTITLE_FMT_BITMAP,  .name = "Graphical subtitles",     },
> +    {.fmt = AV_SUBTITLE_FMT_TEXT,    .name = "Text subtitles (plain)",  },
> +    {.fmt = AV_SUBTITLE_FMT_ASS,     .name = "Text subtitles (ass)",    },
> +};
> +
> +const char *av_get_subtitle_fmt_name(enum AVSubtitleType sub_fmt)
> +{
> +    if (sub_fmt < 0 || sub_fmt >= AV_SUBTITLE_FMT_NB)
> +        return NULL;
> +    return sub_fmt_info[sub_fmt].name;
> +}
> +
> +enum AVSubtitleType av_get_subtitle_fmt(const char *name)
> +{
> +    int i;
> +
> +    for (i = 0; i < AV_SUBTITLE_FMT_NB; i++)
> +        if (!strcmp(sub_fmt_info[i].name, name))
> +            return i;
> +    return AV_SUBTITLE_FMT_NONE;
> +}
> diff --git a/libavutil/subfmt.h b/libavutil/subfmt.h
> new file mode 100644
> index 0000000000..31dabc957c
> --- /dev/null
> +++ b/libavutil/subfmt.h
> @@ -0,0 +1,94 @@
> +/*
> + * Copyright (c) 2021 softworkz
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#ifndef AVUTIL_SUBFMT_H
> +#define AVUTIL_SUBFMT_H
> +
> +#include <inttypes.h>
> +
> +enum AVSubtitleType {
> +
> +    /**
> +     * Subtitle format unknown.
> +     */
> +    AV_SUBTITLE_FMT_NONE = -1,
> +
> +    /**
> +     * Subtitle format unknown.
> +     */
> +    AV_SUBTITLE_FMT_UNKNOWN = 0,
> +
> +    /**
> +     * Bitmap area in AVSubtitleRect.data, pixfmt AV_PIX_FMT_PAL8.
> +     */
> +    AV_SUBTITLE_FMT_BITMAP = 1,
> +
> +    /**
> +     * Plain text in AVSubtitleRect.text.
> +     */
> +    AV_SUBTITLE_FMT_TEXT = 2,
> +
> +    /**
> +     * Text Formatted as per ASS specification, contained AVSubtitleRect.ass.
> +     */
> +    AV_SUBTITLE_FMT_ASS = 3,
> +
> +    AV_SUBTITLE_FMT_NB,
> +};
> +
> +typedef struct AVSubtitleRect {
> +    unsigned nb_refs;

This reference counter (which is off by one compared to an ordinary
reference counter) is nonatomic. This is unacceptable. After all, we are
in a multithreading world.

(We have certain fallback compatibility version for stdatomics; these
are nonpublic headers that are not public and can't even be made public
-- some use avpriv functions that are not part of the public API. So
don't be surprised if it is not feasible to add an atomic refcount to a
public API.)

> +    int x;         ///< top left corner  of pict, undefined when pict is not set
> +    int y;         ///< top left corner  of pict, undefined when pict is not set
> +    int w;         ///< width            of pict, undefined when pict is not set
> +    int h;         ///< height           of pict, undefined when pict is not set
> +    int nb_colors; ///< number of colors in pict, undefined when pict is not set
> +
> +    /**
> +     * data+linesize for the bitmap of this subtitle.
> +     */
> +    uint8_t *data[4];
> +    int linesize[4];
> +
> +    enum AVSubtitleType type;
> +
> +    char *text;                     ///< 0 terminated plain UTF-8 text
> +
> +    /**
> +     * 0-terminated ASS/SSA compatible event line.
> +     */
> +    char *ass;
> +
> +    int flags;
> +} AVSubtitleRect;
> +
> +/**
> + * Return the name of sub_fmt, or NULL if sub_fmt is not
> + * recognized.
> + */
> +const char *av_get_subtitle_fmt_name(enum AVSubtitleType sub_fmt);
> +
> +/**
> + * Return a subtitle format corresponding to name, or AV_SUBTITLE_FMT_NONE
> + * on error.
> + */
> +enum AVSubtitleType av_get_subtitle_fmt(const char *name);
> +
> +#endif /* AVUTIL_SUBFMT_H */
>
diff mbox series

Patch

diff --git a/libavcodec/ass.c b/libavcodec/ass.c
index 907e2d7b88..415ef12911 100644
--- a/libavcodec/ass.c
+++ b/libavcodec/ass.c
@@ -114,26 +114,26 @@  char *ff_ass_get_dialog(int readorder, int layer, const char *style,
                        speaker ? speaker : "", text);
 }
 
-int ff_ass_add_rect(AVSubtitle *sub, const char *dialog,
+int ff_ass_add_rect(AVFrame *sub, const char *dialog,
                     int readorder, int layer, const char *style,
                     const char *speaker)
 {
     char *ass_str;
     AVSubtitleRect **rects;
 
-    rects = av_realloc_array(sub->rects, sub->num_rects+1, sizeof(*sub->rects));
+    rects = av_realloc_array(sub->subtitle_rects, sub->num_subtitle_rects+1, sizeof(*sub->subtitle_rects));
     if (!rects)
         return AVERROR(ENOMEM);
-    sub->rects = rects;
-    rects[sub->num_rects]       = av_mallocz(sizeof(*rects[0]));
-    if (!rects[sub->num_rects])
+    sub->subtitle_rects = rects;
+    rects[sub->num_subtitle_rects]       = av_mallocz(sizeof(*rects[0]));
+    if (!rects[sub->num_subtitle_rects])
         return AVERROR(ENOMEM);
-    rects[sub->num_rects]->type = SUBTITLE_ASS;
+    rects[sub->num_subtitle_rects]->type = AV_SUBTITLE_FMT_ASS;
     ass_str = ff_ass_get_dialog(readorder, layer, style, speaker, dialog);
     if (!ass_str)
         return AVERROR(ENOMEM);
-    rects[sub->num_rects]->ass = ass_str;
-    sub->num_rects++;
+    rects[sub->num_subtitle_rects]->ass = ass_str;
+    sub->num_subtitle_rects++;
     return 0;
 }
 
diff --git a/libavcodec/ass.h b/libavcodec/ass.h
index 2c260e4e78..de31f35c8a 100644
--- a/libavcodec/ass.h
+++ b/libavcodec/ass.h
@@ -48,7 +48,7 @@  typedef struct FFASSDecoderContext {
 } FFASSDecoderContext;
 
 /**
- * Generate a suitable AVCodecContext.subtitle_header for SUBTITLE_ASS.
+ * Generate a suitable AVCodecContext.subtitle_header for AV_SUBTITLE_FMT_ASS.
  * Can specify all fields explicitly
  *
  * @param avctx pointer to the AVCodecContext
@@ -76,7 +76,7 @@  int ff_ass_subtitle_header_full(AVCodecContext *avctx,
                                 int bold, int italic, int underline,
                                 int border_style, int alignment);
 /**
- * Generate a suitable AVCodecContext.subtitle_header for SUBTITLE_ASS.
+ * Generate a suitable AVCodecContext.subtitle_header for AV_SUBTITLE_FMT_ASS.
  *
  * @param avctx pointer to the AVCodecContext
  * @param font name of the default font face to use
@@ -97,7 +97,7 @@  int ff_ass_subtitle_header(AVCodecContext *avctx,
                            int border_style, int alignment);
 
 /**
- * Generate a suitable AVCodecContext.subtitle_header for SUBTITLE_ASS
+ * Generate a suitable AVCodecContext.subtitle_header for AV_SUBTITLE_FMT_ASS
  * with default style.
  *
  * @param avctx pointer to the AVCodecContext
@@ -114,7 +114,7 @@  char *ff_ass_get_dialog(int readorder, int layer, const char *style,
 /**
  * Add an ASS dialog to a subtitle.
  */
-int ff_ass_add_rect(AVSubtitle *sub, const char *dialog,
+int ff_ass_add_rect(AVFrame *sub, const char *dialog,
                     int readorder, int layer, const char *style,
                     const char *speaker);
 
diff --git a/libavcodec/assdec.c b/libavcodec/assdec.c
index 319279490c..0df08ba756 100644
--- a/libavcodec/assdec.c
+++ b/libavcodec/assdec.c
@@ -42,21 +42,21 @@  static av_cold int ass_decode_init(AVCodecContext *avctx)
 static int ass_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr,
                             AVPacket *avpkt)
 {
-    AVSubtitle *sub = data;
+    AVFrame *sub = data;
 
     if (avpkt->size <= 0)
         return avpkt->size;
 
-    sub->rects = av_malloc(sizeof(*sub->rects));
-    if (!sub->rects)
+    sub->subtitle_rects = av_malloc(sizeof(*sub->subtitle_rects));
+    if (!sub->subtitle_rects)
         return AVERROR(ENOMEM);
-    sub->rects[0] = av_mallocz(sizeof(*sub->rects[0]));
-    if (!sub->rects[0])
+    sub->subtitle_rects[0] = av_mallocz(sizeof(*sub->subtitle_rects[0]));
+    if (!sub->subtitle_rects[0])
         return AVERROR(ENOMEM);
-    sub->num_rects = 1;
-    sub->rects[0]->type = SUBTITLE_ASS;
-    sub->rects[0]->ass  = av_strdup(avpkt->data);
-    if (!sub->rects[0]->ass)
+    sub->num_subtitle_rects = 1;
+    sub->subtitle_rects[0]->type = AV_SUBTITLE_FMT_ASS;
+    sub->subtitle_rects[0]->ass  = av_strdup(avpkt->data);
+    if (!sub->subtitle_rects[0]->ass)
         return AVERROR(ENOMEM);
     *got_sub_ptr = 1;
     return avpkt->size;
diff --git a/libavcodec/assenc.c b/libavcodec/assenc.c
index a6d107ded2..84745a4487 100644
--- a/libavcodec/assenc.c
+++ b/libavcodec/assenc.c
@@ -41,15 +41,15 @@  static av_cold int ass_encode_init(AVCodecContext *avctx)
 
 static int ass_encode_frame(AVCodecContext *avctx,
                             unsigned char *buf, int bufsize,
-                            const AVSubtitle *sub)
+                            const AVFrame *sub)
 {
     int i, len, total_len = 0;
 
-    for (i=0; i<sub->num_rects; i++) {
-        const char *ass = sub->rects[i]->ass;
+    for (i=0; i<sub->num_subtitle_rects; i++) {
+        const char *ass = sub->subtitle_rects[i]->ass;
 
-        if (sub->rects[i]->type != SUBTITLE_ASS) {
-            av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
+        if (sub->subtitle_rects[i]->type != AV_SUBTITLE_FMT_ASS) {
+            av_log(avctx, AV_LOG_ERROR, "Only AV_SUBTITLE_FMT_ASS type supported.\n");
             return AVERROR(EINVAL);
         }
 
diff --git a/libavcodec/avcodec.c b/libavcodec/avcodec.c
index 2dd7dd84e0..963f52c4bd 100644
--- a/libavcodec/avcodec.c
+++ b/libavcodec/avcodec.c
@@ -426,25 +426,6 @@  void avcodec_flush_buffers(AVCodecContext *avctx)
         av_bsf_flush(avci->bsf);
 }
 
-void avsubtitle_free(AVSubtitle *sub)
-{
-    int i;
-
-    for (i = 0; i < sub->num_rects; i++) {
-        av_freep(&sub->rects[i]->data[0]);
-        av_freep(&sub->rects[i]->data[1]);
-        av_freep(&sub->rects[i]->data[2]);
-        av_freep(&sub->rects[i]->data[3]);
-        av_freep(&sub->rects[i]->text);
-        av_freep(&sub->rects[i]->ass);
-        av_freep(&sub->rects[i]);
-    }
-
-    av_freep(&sub->rects);
-
-    memset(sub, 0, sizeof(*sub));
-}
-
 av_cold int avcodec_close(AVCodecContext *avctx)
 {
     int i;
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index ffd58c333f..a7a2df8cf4 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -35,6 +35,7 @@ 
 #include "libavutil/frame.h"
 #include "libavutil/log.h"
 #include "libavutil/pixfmt.h"
+#include "libavutil/subfmt.h"
 #include "libavutil/rational.h"
 
 #include "codec.h"
@@ -1670,7 +1671,7 @@  typedef struct AVCodecContext {
 
     /**
      * Header containing style information for text subtitles.
-     * For SUBTITLE_ASS subtitle type, it should contain the whole ASS
+     * For AV_SUBTITLE_FMT_ASS subtitle type, it should contain the whole ASS
      * [Script Info] and [V4+ Styles] section, plus the [Events] line and
      * the Format line following. It shouldn't include any Dialogue line.
      * - encoding: Set/allocated/freed by user (before avcodec_open2())
@@ -2233,63 +2234,8 @@  typedef struct AVHWAccel {
  * @}
  */
 
-enum AVSubtitleType {
-    SUBTITLE_NONE,
-
-    SUBTITLE_BITMAP,                ///< A bitmap, pict will be set
-
-    /**
-     * Plain text, the text field must be set by the decoder and is
-     * authoritative. ass and pict fields may contain approximations.
-     */
-    SUBTITLE_TEXT,
-
-    /**
-     * Formatted text, the ass field must be set by the decoder and is
-     * authoritative. pict and text fields may contain approximations.
-     */
-    SUBTITLE_ASS,
-};
-
 #define AV_SUBTITLE_FLAG_FORCED 0x00000001
 
-typedef struct AVSubtitleRect {
-    int x;         ///< top left corner  of pict, undefined when pict is not set
-    int y;         ///< top left corner  of pict, undefined when pict is not set
-    int w;         ///< width            of pict, undefined when pict is not set
-    int h;         ///< height           of pict, undefined when pict is not set
-    int nb_colors; ///< number of colors in pict, undefined when pict is not set
-
-    /**
-     * data+linesize for the bitmap of this subtitle.
-     * Can be set for text/ass as well once they are rendered.
-     */
-    uint8_t *data[4];
-    int linesize[4];
-
-    enum AVSubtitleType type;
-
-    char *text;                     ///< 0 terminated plain UTF-8 text
-
-    /**
-     * 0 terminated ASS/SSA compatible event line.
-     * The presentation of this is unaffected by the other values in this
-     * struct.
-     */
-    char *ass;
-
-    int flags;
-} AVSubtitleRect;
-
-typedef struct AVSubtitle {
-    uint16_t format; /* 0 = graphics */
-    uint32_t start_display_time; /* relative to packet pts, in ms */
-    uint32_t end_display_time; /* relative to packet pts, in ms */
-    unsigned num_rects;
-    AVSubtitleRect **rects;
-    int64_t pts;    ///< Same as packet pts, in AV_TIME_BASE
-} AVSubtitle;
-
 /**
  * Return the LIBAVCODEC_VERSION_INT constant.
  */
@@ -2425,13 +2371,6 @@  int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **op
  */
 int avcodec_close(AVCodecContext *avctx);
 
-/**
- * Free all allocated data in the given subtitle struct.
- *
- * @param sub AVSubtitle to free.
- */
-void avsubtitle_free(AVSubtitle *sub);
-
 /**
  * @}
  */
@@ -2518,12 +2457,12 @@  enum AVChromaLocation avcodec_chroma_pos_to_enum(int xpos, int ypos);
  * before packets may be fed to the decoder.
  *
  * @param avctx the codec context
- * @param[out] sub The preallocated AVSubtitle in which the decoded subtitle will be stored,
- *                 must be freed with avsubtitle_free if *got_sub_ptr is set.
+ * @param[out] sub The preallocated AVFrame in which the decoded subtitle will be stored,
+ *                 must be freed with av_frame_free if *got_sub_ptr is set.
  * @param[in,out] got_sub_ptr Zero if no subtitle could be decompressed, otherwise, it is nonzero.
  * @param[in] avpkt The input AVPacket containing the input buffer.
  */
-int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
+int avcodec_decode_subtitle2(AVCodecContext *avctx, AVFrame *sub,
                             int *got_sub_ptr,
                             AVPacket *avpkt);
 
@@ -3004,7 +2943,7 @@  void av_parser_close(AVCodecParserContext *s);
  */
 
 int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size,
-                            const AVSubtitle *sub);
+                            const AVFrame *sub);
 
 
 /**
@@ -3120,6 +3059,14 @@  void avcodec_flush_buffers(AVCodecContext *avctx);
  */
 int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes);
 
+/**
+ * Return subtitle format from a codec descriptor
+ *
+ * @param codec_descriptor codec descriptor
+ * @return                 the subtitle type (e.g. bitmap, text)
+ */
+enum AVSubtitleType av_get_subtitle_format_from_codecdesc(const AVCodecDescriptor *codec_descriptor);
+
 /* memory */
 
 /**
diff --git a/libavcodec/ccaption_dec.c b/libavcodec/ccaption_dec.c
index 27c61527f6..33cc88f705 100644
--- a/libavcodec/ccaption_dec.c
+++ b/libavcodec/ccaption_dec.c
@@ -841,8 +841,8 @@  static int process_cc608(CCaptionSubContext *ctx, uint8_t hi, uint8_t lo)
 static int decode(AVCodecContext *avctx, void *data, int *got_sub, AVPacket *avpkt)
 {
     CCaptionSubContext *ctx = avctx->priv_data;
-    AVSubtitle *sub = data;
-    int64_t in_time = sub->pts;
+    AVFrame *sub = data;
+    int64_t in_time = sub->subtitle_pts;
     int64_t start_time;
     int64_t end_time;
     int bidx = ctx->buffer_index;
@@ -879,17 +879,17 @@  static int decode(AVCodecContext *avctx, void *data, int *got_sub, AVPacket *avp
         if (ctx->buffer[bidx].str[0] || ctx->real_time) {
             ff_dlog(ctx, "cdp writing data (%s)\n", ctx->buffer[bidx].str);
             start_time = ctx->buffer_time[0];
-            sub->pts = start_time;
+            sub->subtitle_pts = start_time;
             end_time = ctx->buffer_time[1];
             if (!ctx->real_time)
-                sub->end_display_time = av_rescale_q(end_time - start_time,
+                sub->subtitle_end_time = av_rescale_q(end_time - start_time,
                                                      AV_TIME_BASE_Q, ms_tb);
             else
-                sub->end_display_time = -1;
+                sub->subtitle_end_time = -1;
             ret = ff_ass_add_rect(sub, ctx->buffer[bidx].str, ctx->readorder++, 0, NULL, NULL);
             if (ret < 0)
                 return ret;
-            ctx->last_real_time = sub->pts;
+            ctx->last_real_time = sub->subtitle_pts;
             ctx->screen_touched = 0;
         }
     }
@@ -899,16 +899,16 @@  static int decode(AVCodecContext *avctx, void *data, int *got_sub, AVPacket *avp
         ret = ff_ass_add_rect(sub, ctx->buffer[bidx].str, ctx->readorder++, 0, NULL, NULL);
         if (ret < 0)
             return ret;
-        sub->pts = ctx->buffer_time[1];
-        sub->end_display_time = av_rescale_q(ctx->buffer_time[1] - ctx->buffer_time[0],
+        sub->subtitle_pts = ctx->buffer_time[1];
+        sub->subtitle_end_time = av_rescale_q(ctx->buffer_time[1] - ctx->buffer_time[0],
                                              AV_TIME_BASE_Q, ms_tb);
-        if (sub->end_display_time == 0)
-            sub->end_display_time = ctx->buffer[bidx].len * 20;
+        if (sub->subtitle_end_time == 0)
+            sub->subtitle_end_time = ctx->buffer[bidx].len * 20;
     }
 
     if (ctx->real_time && ctx->screen_touched &&
-        sub->pts >= ctx->last_real_time + av_rescale_q(ctx->real_time_latency_msec, ms_tb, AV_TIME_BASE_Q)) {
-        ctx->last_real_time = sub->pts;
+        sub->subtitle_pts >= ctx->last_real_time + av_rescale_q(ctx->real_time_latency_msec, ms_tb, AV_TIME_BASE_Q)) {
+        ctx->last_real_time = sub->subtitle_pts;
         ctx->screen_touched = 0;
 
         capture_screen(ctx);
@@ -917,10 +917,10 @@  static int decode(AVCodecContext *avctx, void *data, int *got_sub, AVPacket *avp
         ret = ff_ass_add_rect(sub, ctx->buffer[bidx].str, ctx->readorder++, 0, NULL, NULL);
         if (ret < 0)
             return ret;
-        sub->end_display_time = -1;
+        sub->subtitle_end_time = -1;
     }
 
-    *got_sub = sub->num_rects > 0;
+    *got_sub = sub->num_subtitle_rects > 0;
     return ret;
 }
 
diff --git a/libavcodec/codec.h b/libavcodec/codec.h
index 8f12705066..785a6bf27e 100644
--- a/libavcodec/codec.h
+++ b/libavcodec/codec.h
@@ -188,7 +188,7 @@  typedef struct AVProfile {
 typedef struct AVCodecDefault AVCodecDefault;
 
 struct AVCodecContext;
-struct AVSubtitle;
+struct AVFrame;
 struct AVPacket;
 
 /**
@@ -283,7 +283,7 @@  typedef struct AVCodec {
 
     int (*init)(struct AVCodecContext *);
     int (*encode_sub)(struct AVCodecContext *, uint8_t *buf, int buf_size,
-                      const struct AVSubtitle *sub);
+                      const struct AVFrame *sub);
     /**
      * Encode data to an AVPacket.
      *
diff --git a/libavcodec/codec_desc.h b/libavcodec/codec_desc.h
index 126b52df47..387863a041 100644
--- a/libavcodec/codec_desc.h
+++ b/libavcodec/codec_desc.h
@@ -92,12 +92,12 @@  typedef struct AVCodecDescriptor {
 #define AV_CODEC_PROP_REORDER       (1 << 3)
 /**
  * Subtitle codec is bitmap based
- * Decoded AVSubtitle data can be read from the AVSubtitleRect->pict field.
+ * Decoded AVFrame data can be read from the AVSubtitleRect->pict field.
  */
 #define AV_CODEC_PROP_BITMAP_SUB    (1 << 16)
 /**
  * Subtitle codec is text based.
- * Decoded AVSubtitle data can be read from the AVSubtitleRect->ass field.
+ * Decoded AVFrame data can be read from the AVSubtitleRect->ass field.
  */
 #define AV_CODEC_PROP_TEXT_SUB      (1 << 17)
 
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 643f9d6a30..37dd69070e 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -712,10 +712,10 @@  int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *fr
     return 0;
 }
 
-static void get_subtitle_defaults(AVSubtitle *sub)
+static void get_subtitle_defaults(AVFrame *sub)
 {
     memset(sub, 0, sizeof(*sub));
-    sub->pts = AV_NOPTS_VALUE;
+    sub->subtitle_pts = AV_NOPTS_VALUE;
 }
 
 #define UTF8_MAX_BYTES 4 /* 5 and 6 bytes sequences should not be used */
@@ -799,7 +799,7 @@  static int utf8_check(const uint8_t *str)
     return 1;
 }
 
-int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
+int avcodec_decode_subtitle2(AVCodecContext *avctx, AVFrame *sub,
                              int *got_sub_ptr,
                              AVPacket *avpkt)
 {
@@ -828,31 +828,28 @@  int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
             return ret;
 
         if (avctx->pkt_timebase.num && avpkt->pts != AV_NOPTS_VALUE)
-            sub->pts = av_rescale_q(avpkt->pts,
+            sub->subtitle_pts = av_rescale_q(avpkt->pts,
                                     avctx->pkt_timebase, AV_TIME_BASE_Q);
         ret = avctx->codec->decode(avctx, sub, got_sub_ptr, pkt);
         av_assert1((ret >= 0) >= !!*got_sub_ptr &&
                    !!*got_sub_ptr >= !!sub->num_rects);
 
-        if (sub->num_rects && !sub->end_display_time && avpkt->duration &&
+        if (sub->num_subtitle_rects && !sub->subtitle_end_time && avpkt->duration &&
             avctx->pkt_timebase.num) {
             AVRational ms = { 1, 1000 };
-            sub->end_display_time = av_rescale_q(avpkt->duration,
+            sub->subtitle_end_time = av_rescale_q(avpkt->duration,
                                                  avctx->pkt_timebase, ms);
         }
 
-        if (avctx->codec_descriptor->props & AV_CODEC_PROP_BITMAP_SUB)
-            sub->format = 0;
-        else if (avctx->codec_descriptor->props & AV_CODEC_PROP_TEXT_SUB)
-            sub->format = 1;
+        sub->format = av_get_subtitle_format_from_codecdesc(avctx->codec_descriptor);
 
-        for (unsigned i = 0; i < sub->num_rects; i++) {
+        for (unsigned i = 0; i < sub->num_subtitle_rects; i++) {
             if (avctx->sub_charenc_mode != FF_SUB_CHARENC_MODE_IGNORE &&
-                sub->rects[i]->ass && !utf8_check(sub->rects[i]->ass)) {
+                sub->subtitle_rects[i]->ass && !utf8_check(sub->subtitle_rects[i]->ass)) {
                 av_log(avctx, AV_LOG_ERROR,
                        "Invalid UTF-8 in decoded subtitles text; "
                        "maybe missing -sub_charenc option\n");
-                avsubtitle_free(sub);
+                av_frame_free(&sub);
                 ret = AVERROR_INVALIDDATA;
                 break;
             }
diff --git a/libavcodec/dvbsubdec.c b/libavcodec/dvbsubdec.c
index e45c14e878..aeb88df06f 100644
--- a/libavcodec/dvbsubdec.c
+++ b/libavcodec/dvbsubdec.c
@@ -725,7 +725,7 @@  static void compute_default_clut(DVBSubContext *ctx, uint8_t *clut, AVSubtitleRe
 }
 
 
-static int save_subtitle_set(AVCodecContext *avctx, AVSubtitle *sub, int *got_output)
+static int save_subtitle_set(AVCodecContext *avctx, AVFrame *sub, int *got_output)
 {
     DVBSubContext *ctx = avctx->priv_data;
     DVBSubRegionDisplay *display;
@@ -745,34 +745,34 @@  static int save_subtitle_set(AVCodecContext *avctx, AVSubtitle *sub, int *got_ou
     }
 
     /* Not touching AVSubtitles again*/
-    if (sub->num_rects) {
+    if (sub->num_subtitle_rects) {
         avpriv_request_sample(ctx, "Different Version of Segment asked Twice");
         return AVERROR_PATCHWELCOME;
     }
     for (display = ctx->display_list; display; display = display->next) {
         region = get_region(ctx, display->region_id);
         if (region && region->dirty)
-            sub->num_rects++;
+            sub->num_subtitle_rects++;
     }
 
     if (ctx->compute_edt == 0) {
-        sub->end_display_time = ctx->time_out * 1000;
+        sub->subtitle_end_time = ctx->time_out * 1000;
         *got_output = 1;
     } else if (ctx->prev_start != AV_NOPTS_VALUE) {
-        sub->end_display_time = av_rescale_q((sub->pts - ctx->prev_start ), AV_TIME_BASE_Q, (AVRational){ 1, 1000 }) - 1;
+        sub->subtitle_end_time = av_rescale_q((sub->subtitle_pts - ctx->prev_start ), AV_TIME_BASE_Q, (AVRational){ 1, 1000 }) - 1;
         *got_output = 1;
     }
-    if (sub->num_rects > 0) {
+    if (sub->num_subtitle_rects > 0) {
 
-        sub->rects = av_mallocz_array(sizeof(*sub->rects), sub->num_rects);
-        if (!sub->rects) {
+        sub->subtitle_rects = av_mallocz_array(sizeof(*sub->subtitle_rects), sub->num_subtitle_rects);
+        if (!sub->subtitle_rects) {
             ret = AVERROR(ENOMEM);
             goto fail;
         }
 
-        for (i = 0; i < sub->num_rects; i++) {
-            sub->rects[i] = av_mallocz(sizeof(*sub->rects[i]));
-            if (!sub->rects[i]) {
+        for (i = 0; i < sub->num_subtitle_rects; i++) {
+            sub->subtitle_rects[i] = av_mallocz(sizeof(*sub->subtitle_rects[i]));
+            if (!sub->subtitle_rects[i]) {
                 ret = AVERROR(ENOMEM);
                 goto fail;
             }
@@ -789,13 +789,13 @@  static int save_subtitle_set(AVCodecContext *avctx, AVSubtitle *sub, int *got_ou
             if (!region->dirty)
                 continue;
 
-            rect = sub->rects[i];
+            rect = sub->subtitle_rects[i];
             rect->x = display->x_pos + offset_x;
             rect->y = display->y_pos + offset_y;
             rect->w = region->width;
             rect->h = region->height;
             rect->nb_colors = (1 << region->depth);
-            rect->type      = SUBTITLE_BITMAP;
+            rect->type      = AV_SUBTITLE_FMT_BITMAP;
             rect->linesize[0] = region->width;
 
             clut = get_clut(ctx, region->clut);
@@ -846,18 +846,18 @@  static int save_subtitle_set(AVCodecContext *avctx, AVSubtitle *sub, int *got_ou
 
     return 0;
 fail:
-    if (sub->rects) {
-        for (i=0; i < sub->num_rects; i++) {
-            rect = sub->rects[i];
+    if (sub->subtitle_rects) {
+        for (i=0; i < sub->num_subtitle_rects; i++) {
+            rect = sub->subtitle_rects[i];
             if (rect) {
                 av_freep(&rect->data[0]);
                 av_freep(&rect->data[1]);
             }
-            av_freep(&sub->rects[i]);
+            av_freep(&sub->subtitle_rects[i]);
         }
-        av_freep(&sub->rects);
+        av_freep(&sub->subtitle_rects);
     }
-    sub->num_rects = 0;
+    sub->num_subtitle_rects = 0;
     return ret;
 }
 
@@ -1291,7 +1291,7 @@  static int dvbsub_parse_region_segment(AVCodecContext *avctx,
 }
 
 static int dvbsub_parse_page_segment(AVCodecContext *avctx,
-                                     const uint8_t *buf, int buf_size, AVSubtitle *sub, int *got_output)
+                                     const uint8_t *buf, int buf_size, AVFrame *sub, int *got_output)
 {
     DVBSubContext *ctx = avctx->priv_data;
     DVBSubRegionDisplay *display;
@@ -1598,7 +1598,7 @@  static int dvbsub_parse_display_definition_segment(AVCodecContext *avctx,
 }
 
 static int dvbsub_display_end_segment(AVCodecContext *avctx, const uint8_t *buf,
-                                      int buf_size, AVSubtitle *sub,int *got_output)
+                                      int buf_size, AVFrame *sub,int *got_output)
 {
     DVBSubContext *ctx = avctx->priv_data;
 
@@ -1617,7 +1617,7 @@  static int dvbsub_decode(AVCodecContext *avctx,
     const uint8_t *buf = avpkt->data;
     int buf_size = avpkt->size;
     DVBSubContext *ctx = avctx->priv_data;
-    AVSubtitle *sub = data;
+    AVFrame *sub = data;
     const uint8_t *p, *p_end;
     int segment_type;
     int page_id;
@@ -1720,11 +1720,11 @@  static int dvbsub_decode(AVCodecContext *avctx,
 end:
     if (ret < 0) {
         *got_sub_ptr = 0;
-        avsubtitle_free(sub);
+        av_frame_free(&sub);
         return ret;
     } else {
         if (ctx->compute_edt == 1)
-            FFSWAP(int64_t, ctx->prev_start, sub->pts);
+            FFSWAP(int64_t, ctx->prev_start, sub->subtitle_pts);
     }
 
     return p - buf;
diff --git a/libavcodec/dvbsubenc.c b/libavcodec/dvbsubenc.c
index 322fc27cb4..480092867e 100644
--- a/libavcodec/dvbsubenc.c
+++ b/libavcodec/dvbsubenc.c
@@ -269,7 +269,7 @@  static int dvb_encode_rle8(uint8_t **pq, int buf_size,
 }
 
 static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
-                         const AVSubtitle *h)
+                         const AVFrame *h)
 {
     DVBSubtitleContext *s = avctx->priv_data;
     uint8_t *q, *pseg_len;
@@ -280,7 +280,7 @@  static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
 
     page_id = 1;
 
-    if (h->num_rects && !h->rects)
+    if (h->num_subtitle_rects && !h->subtitle_rects)
         return AVERROR(EINVAL);
 
     if (avctx->width > 0 && avctx->height > 0) {
@@ -301,7 +301,7 @@  static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
 
     /* page composition segment */
 
-    if (buf_size < 8 + h->num_rects * 6)
+    if (buf_size < 8 + h->num_subtitle_rects * 6)
         return AVERROR_BUFFER_TOO_SMALL;
     *q++ = 0x0f; /* sync_byte */
     *q++ = 0x10; /* segment_type */
@@ -313,30 +313,30 @@  static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
     /* page_version = 0 + page_state */
     *q++ = (s->object_version << 4) | (page_state << 2) | 3;
 
-    for (region_id = 0; region_id < h->num_rects; region_id++) {
+    for (region_id = 0; region_id < h->num_subtitle_rects; region_id++) {
         *q++ = region_id;
         *q++ = 0xff; /* reserved */
-        bytestream_put_be16(&q, h->rects[region_id]->x); /* left pos */
-        bytestream_put_be16(&q, h->rects[region_id]->y); /* top pos */
+        bytestream_put_be16(&q, h->subtitle_rects[region_id]->x); /* left pos */
+        bytestream_put_be16(&q, h->subtitle_rects[region_id]->y); /* top pos */
     }
 
     bytestream_put_be16(&pseg_len, q - pseg_len - 2);
-    buf_size -= 8 + h->num_rects * 6;
+    buf_size -= 8 + h->num_subtitle_rects * 6;
 
-    if (h->num_rects) {
-        for (clut_id = 0; clut_id < h->num_rects; clut_id++) {
-            if (buf_size < 6 + h->rects[clut_id]->nb_colors * 6)
+    if (h->num_subtitle_rects) {
+        for (clut_id = 0; clut_id < h->num_subtitle_rects; clut_id++) {
+            if (buf_size < 6 + h->subtitle_rects[clut_id]->nb_colors * 6)
                 return AVERROR_BUFFER_TOO_SMALL;
 
             /* CLUT segment */
 
-            if (h->rects[clut_id]->nb_colors <= 4) {
+            if (h->subtitle_rects[clut_id]->nb_colors <= 4) {
                 /* 2 bpp, some decoders do not support it correctly */
                 bpp_index = 0;
-            } else if (h->rects[clut_id]->nb_colors <= 16) {
+            } else if (h->subtitle_rects[clut_id]->nb_colors <= 16) {
                 /* 4 bpp, standard encoding */
                 bpp_index = 1;
-            } else if (h->rects[clut_id]->nb_colors <= 256) {
+            } else if (h->subtitle_rects[clut_id]->nb_colors <= 256) {
                 /* 8 bpp, standard encoding */
                 bpp_index = 2;
             } else {
@@ -353,12 +353,12 @@  static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
             *q++ = clut_id;
             *q++ = (0 << 4) | 0xf; /* version = 0 */
 
-            for(i = 0; i < h->rects[clut_id]->nb_colors; i++) {
+            for(i = 0; i < h->subtitle_rects[clut_id]->nb_colors; i++) {
                 *q++ = i; /* clut_entry_id */
                 *q++ = (1 << (7 - bpp_index)) | (0xf << 1) | 1; /* 2 bits/pixel full range */
                 {
                     int a, r, g, b;
-                    uint32_t x= ((uint32_t*)h->rects[clut_id]->data[1])[i];
+                    uint32_t x= ((uint32_t*)h->subtitle_rects[clut_id]->data[1])[i];
                     a = (x >> 24) & 0xff;
                     r = (x >> 16) & 0xff;
                     g = (x >>  8) & 0xff;
@@ -372,22 +372,22 @@  static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
             }
 
             bytestream_put_be16(&pseg_len, q - pseg_len - 2);
-            buf_size -= 6 + h->rects[clut_id]->nb_colors * 6;
+            buf_size -= 6 + h->subtitle_rects[clut_id]->nb_colors * 6;
         }
 
-        if (buf_size < h->num_rects * 22)
+        if (buf_size < h->num_subtitle_rects * 22)
             return AVERROR_BUFFER_TOO_SMALL;
-        for (region_id = 0; region_id < h->num_rects; region_id++) {
+        for (region_id = 0; region_id < h->num_subtitle_rects; region_id++) {
 
             /* region composition segment */
 
-            if (h->rects[region_id]->nb_colors <= 4) {
+            if (h->subtitle_rects[region_id]->nb_colors <= 4) {
                 /* 2 bpp, some decoders do not support it correctly */
                 bpp_index = 0;
-            } else if (h->rects[region_id]->nb_colors <= 16) {
+            } else if (h->subtitle_rects[region_id]->nb_colors <= 16) {
                 /* 4 bpp, standard encoding */
                 bpp_index = 1;
-            } else if (h->rects[region_id]->nb_colors <= 256) {
+            } else if (h->subtitle_rects[region_id]->nb_colors <= 256) {
                 /* 8 bpp, standard encoding */
                 bpp_index = 2;
             } else {
@@ -401,8 +401,8 @@  static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
             q += 2; /* segment length */
             *q++ = region_id;
             *q++ = (s->object_version << 4) | (0 << 3) | 0x07; /* version , no fill */
-            bytestream_put_be16(&q, h->rects[region_id]->w); /* region width */
-            bytestream_put_be16(&q, h->rects[region_id]->h); /* region height */
+            bytestream_put_be16(&q, h->subtitle_rects[region_id]->w); /* region width */
+            bytestream_put_be16(&q, h->subtitle_rects[region_id]->h); /* region height */
             *q++ = ((1 + bpp_index) << 5) | ((1 + bpp_index) << 2) | 0x03;
             *q++ = region_id; /* clut_id == region_id */
             *q++ = 0; /* 8 bit fill colors */
@@ -416,9 +416,9 @@  static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
 
             bytestream_put_be16(&pseg_len, q - pseg_len - 2);
         }
-        buf_size -= h->num_rects * 22;
+        buf_size -= h->num_subtitle_rects * 22;
 
-        for (object_id = 0; object_id < h->num_rects; object_id++) {
+        for (object_id = 0; object_id < h->num_subtitle_rects; object_id++) {
             int (*dvb_encode_rle)(uint8_t **pq, int buf_size,
                                   const uint8_t *bitmap, int linesize,
                                   int w, int h);
@@ -427,13 +427,13 @@  static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
                 return AVERROR_BUFFER_TOO_SMALL;
 
             /* bpp_index maths */
-            if (h->rects[object_id]->nb_colors <= 4) {
+            if (h->subtitle_rects[object_id]->nb_colors <= 4) {
                 /* 2 bpp, some decoders do not support it correctly */
                 dvb_encode_rle = dvb_encode_rle2;
-            } else if (h->rects[object_id]->nb_colors <= 16) {
+            } else if (h->subtitle_rects[object_id]->nb_colors <= 16) {
                 /* 4 bpp, standard encoding */
                 dvb_encode_rle = dvb_encode_rle4;
-            } else if (h->rects[object_id]->nb_colors <= 256) {
+            } else if (h->subtitle_rects[object_id]->nb_colors <= 256) {
                 /* 8 bpp, standard encoding */
                 dvb_encode_rle = dvb_encode_rle8;
             } else {
@@ -463,19 +463,19 @@  static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
 
                 top_ptr = q;
                 ret = dvb_encode_rle(&q, buf_size,
-                                     h->rects[object_id]->data[0],
-                                     h->rects[object_id]->w * 2,
-                                     h->rects[object_id]->w,
-                                     h->rects[object_id]->h >> 1);
+                                     h->subtitle_rects[object_id]->data[0],
+                                     h->subtitle_rects[object_id]->w * 2,
+                                     h->subtitle_rects[object_id]->w,
+                                     h->subtitle_rects[object_id]->h >> 1);
                 if (ret < 0)
                     return ret;
                 buf_size -= ret;
                 bottom_ptr = q;
                 ret = dvb_encode_rle(&q, buf_size,
-                                     h->rects[object_id]->data[0] + h->rects[object_id]->w,
-                                     h->rects[object_id]->w * 2,
-                                     h->rects[object_id]->w,
-                                     h->rects[object_id]->h >> 1);
+                                     h->subtitle_rects[object_id]->data[0] + h->subtitle_rects[object_id]->w,
+                                     h->subtitle_rects[object_id]->w * 2,
+                                     h->subtitle_rects[object_id]->w,
+                                     h->subtitle_rects[object_id]->h >> 1);
                 if (ret < 0)
                     return ret;
                 buf_size -= ret;
diff --git a/libavcodec/dvdsubdec.c b/libavcodec/dvdsubdec.c
index 52259f0730..6c7b315026 100644
--- a/libavcodec/dvdsubdec.c
+++ b/libavcodec/dvdsubdec.c
@@ -200,24 +200,24 @@  static void guess_palette(DVDSubContext* ctx,
     }
 }
 
-static void reset_rects(AVSubtitle *sub_header)
+static void reset_rects(AVFrame *sub_header)
 {
     int i;
 
-    if (sub_header->rects) {
-        for (i = 0; i < sub_header->num_rects; i++) {
-            av_freep(&sub_header->rects[i]->data[0]);
-            av_freep(&sub_header->rects[i]->data[1]);
-            av_freep(&sub_header->rects[i]);
+    if (sub_header->subtitle_rects) {
+        for (i = 0; i < sub_header->num_subtitle_rects; i++) {
+            av_freep(&sub_header->subtitle_rects[i]->data[0]);
+            av_freep(&sub_header->subtitle_rects[i]->data[1]);
+            av_freep(&sub_header->subtitle_rects[i]);
         }
-        av_freep(&sub_header->rects);
-        sub_header->num_rects = 0;
+        av_freep(&sub_header->subtitle_rects);
+        sub_header->num_subtitle_rects = 0;
     }
 }
 
 #define READ_OFFSET(a) (big_offsets ? AV_RB32(a) : AV_RB16(a))
 
-static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
+static int decode_dvd_subtitles(DVDSubContext *ctx, AVFrame *sub_header,
                                 const uint8_t *buf, int buf_size)
 {
     int cmd_pos, pos, cmd, x1, y1, x2, y2, next_cmd_pos;
@@ -273,11 +273,11 @@  static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
                 break;
             case 0x01:
                 /* set start date */
-                sub_header->start_display_time = (date << 10) / 90;
+                sub_header->subtitle_start_time = (date << 10) / 90;
                 break;
             case 0x02:
                 /* set end date */
-                sub_header->end_display_time = (date << 10) / 90;
+                sub_header->subtitle_end_time = (date << 10) / 90;
                 break;
             case 0x03:
                 /* set colormap */
@@ -371,14 +371,14 @@  static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
             if (w > 0 && h > 1) {
                 reset_rects(sub_header);
                 memset(ctx->used_color, 0, sizeof(ctx->used_color));
-                sub_header->rects = av_mallocz(sizeof(*sub_header->rects));
-                if (!sub_header->rects)
+                sub_header->subtitle_rects = av_mallocz(sizeof(*sub_header->subtitle_rects));
+                if (!sub_header->subtitle_rects)
                     goto fail;
-                sub_header->rects[0] = av_mallocz(sizeof(AVSubtitleRect));
-                if (!sub_header->rects[0])
+                sub_header->subtitle_rects[0] = av_mallocz(sizeof(AVSubtitleRect));
+                if (!sub_header->subtitle_rects[0])
                     goto fail;
-                sub_header->num_rects = 1;
-                bitmap = sub_header->rects[0]->data[0] = av_malloc(w * h);
+                sub_header->num_subtitle_rects = 1;
+                bitmap = sub_header->subtitle_rects[0]->data[0] = av_malloc(w * h);
                 if (!bitmap)
                     goto fail;
                 if (decode_rle(bitmap, w * 2, w, (h + 1) / 2, ctx->used_color,
@@ -387,28 +387,28 @@  static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
                 if (decode_rle(bitmap + w, w * 2, w, h / 2, ctx->used_color,
                                buf, offset2, buf_size, is_8bit) < 0)
                     goto fail;
-                sub_header->rects[0]->data[1] = av_mallocz(AVPALETTE_SIZE);
-                if (!sub_header->rects[0]->data[1])
+                sub_header->subtitle_rects[0]->data[1] = av_mallocz(AVPALETTE_SIZE);
+                if (!sub_header->subtitle_rects[0]->data[1])
                     goto fail;
                 if (is_8bit) {
                     if (!yuv_palette)
                         goto fail;
-                    sub_header->rects[0]->nb_colors = 256;
+                    sub_header->subtitle_rects[0]->nb_colors = 256;
                     yuv_a_to_rgba(yuv_palette, alpha,
-                                  (uint32_t *)sub_header->rects[0]->data[1],
+                                  (uint32_t *)sub_header->subtitle_rects[0]->data[1],
                                   256);
                 } else {
-                    sub_header->rects[0]->nb_colors = 4;
-                    guess_palette(ctx, (uint32_t*)sub_header->rects[0]->data[1],
+                    sub_header->subtitle_rects[0]->nb_colors = 4;
+                    guess_palette(ctx, (uint32_t*)sub_header->subtitle_rects[0]->data[1],
                                   0xffff00);
                 }
-                sub_header->rects[0]->x = x1;
-                sub_header->rects[0]->y = y1;
-                sub_header->rects[0]->w = w;
-                sub_header->rects[0]->h = h;
-                sub_header->rects[0]->type = SUBTITLE_BITMAP;
-                sub_header->rects[0]->linesize[0] = w;
-                sub_header->rects[0]->flags = is_menu ? AV_SUBTITLE_FLAG_FORCED : 0;
+                sub_header->subtitle_rects[0]->x = x1;
+                sub_header->subtitle_rects[0]->y = y1;
+                sub_header->subtitle_rects[0]->w = w;
+                sub_header->subtitle_rects[0]->h = h;
+                sub_header->subtitle_rects[0]->type = AV_SUBTITLE_FMT_BITMAP;
+                sub_header->subtitle_rects[0]->linesize[0] = w;
+                sub_header->subtitle_rects[0]->flags = is_menu ? AV_SUBTITLE_FLAG_FORCED : 0;
             }
         }
         if (next_cmd_pos < cmd_pos) {
@@ -419,7 +419,7 @@  static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
             break;
         cmd_pos = next_cmd_pos;
     }
-    if (sub_header->num_rects > 0)
+    if (sub_header->num_subtitle_rects > 0)
         return is_menu;
  fail:
     reset_rects(sub_header);
@@ -439,18 +439,18 @@  static int is_transp(const uint8_t *buf, int pitch, int n,
 }
 
 /* return 0 if empty rectangle, 1 if non empty */
-static int find_smallest_bounding_rectangle(DVDSubContext *ctx, AVSubtitle *s)
+static int find_smallest_bounding_rectangle(DVDSubContext *ctx, AVFrame *s)
 {
     uint8_t transp_color[256] = { 0 };
     int y1, y2, x1, x2, y, w, h, i;
     uint8_t *bitmap;
     int transparent = 1;
 
-    if (s->num_rects == 0 || !s->rects || s->rects[0]->w <= 0 || s->rects[0]->h <= 0)
+    if (s->num_subtitle_rects == 0 || !s->subtitle_rects || s->subtitle_rects[0]->w <= 0 || s->subtitle_rects[0]->h <= 0)
         return 0;
 
-    for(i = 0; i < s->rects[0]->nb_colors; i++) {
-        if ((((uint32_t *)s->rects[0]->data[1])[i] >> 24) == 0) {
+    for(i = 0; i < s->subtitle_rects[0]->nb_colors; i++) {
+        if ((((uint32_t *)s->subtitle_rects[0]->data[1])[i] >> 24) == 0) {
             transp_color[i] = 1;
         } else if (ctx->used_color[i])
             transparent = 0;
@@ -458,25 +458,25 @@  static int find_smallest_bounding_rectangle(DVDSubContext *ctx, AVSubtitle *s)
     if (transparent)
         return 0;
     y1 = 0;
-    while (y1 < s->rects[0]->h && is_transp(s->rects[0]->data[0] + y1 * s->rects[0]->linesize[0],
-                                  1, s->rects[0]->w, transp_color))
+    while (y1 < s->subtitle_rects[0]->h && is_transp(s->subtitle_rects[0]->data[0] + y1 * s->subtitle_rects[0]->linesize[0],
+                                  1, s->subtitle_rects[0]->w, transp_color))
         y1++;
-    if (y1 == s->rects[0]->h) {
-        av_freep(&s->rects[0]->data[0]);
-        s->rects[0]->w = s->rects[0]->h = 0;
+    if (y1 == s->subtitle_rects[0]->h) {
+        av_freep(&s->subtitle_rects[0]->data[0]);
+        s->subtitle_rects[0]->w = s->subtitle_rects[0]->h = 0;
         return 0;
     }
 
-    y2 = s->rects[0]->h - 1;
-    while (y2 > 0 && is_transp(s->rects[0]->data[0] + y2 * s->rects[0]->linesize[0], 1,
-                               s->rects[0]->w, transp_color))
+    y2 = s->subtitle_rects[0]->h - 1;
+    while (y2 > 0 && is_transp(s->subtitle_rects[0]->data[0] + y2 * s->subtitle_rects[0]->linesize[0], 1,
+                               s->subtitle_rects[0]->w, transp_color))
         y2--;
     x1 = 0;
-    while (x1 < (s->rects[0]->w - 1) && is_transp(s->rects[0]->data[0] + x1, s->rects[0]->linesize[0],
-                                        s->rects[0]->h, transp_color))
+    while (x1 < (s->subtitle_rects[0]->w - 1) && is_transp(s->subtitle_rects[0]->data[0] + x1, s->subtitle_rects[0]->linesize[0],
+                                        s->subtitle_rects[0]->h, transp_color))
         x1++;
-    x2 = s->rects[0]->w - 1;
-    while (x2 > 0 && is_transp(s->rects[0]->data[0] + x2, s->rects[0]->linesize[0], s->rects[0]->h,
+    x2 = s->subtitle_rects[0]->w - 1;
+    while (x2 > 0 && is_transp(s->subtitle_rects[0]->data[0] + x2, s->subtitle_rects[0]->linesize[0], s->subtitle_rects[0]->h,
                                   transp_color))
         x2--;
     w = x2 - x1 + 1;
@@ -485,15 +485,15 @@  static int find_smallest_bounding_rectangle(DVDSubContext *ctx, AVSubtitle *s)
     if (!bitmap)
         return 1;
     for(y = 0; y < h; y++) {
-        memcpy(bitmap + w * y, s->rects[0]->data[0] + x1 + (y1 + y) * s->rects[0]->linesize[0], w);
+        memcpy(bitmap + w * y, s->subtitle_rects[0]->data[0] + x1 + (y1 + y) * s->subtitle_rects[0]->linesize[0], w);
     }
-    av_freep(&s->rects[0]->data[0]);
-    s->rects[0]->data[0] = bitmap;
-    s->rects[0]->linesize[0] = w;
-    s->rects[0]->w = w;
-    s->rects[0]->h = h;
-    s->rects[0]->x += x1;
-    s->rects[0]->y += y1;
+    av_freep(&s->subtitle_rects[0]->data[0]);
+    s->subtitle_rects[0]->data[0] = bitmap;
+    s->subtitle_rects[0]->linesize[0] = w;
+    s->subtitle_rects[0]->w = w;
+    s->subtitle_rects[0]->h = h;
+    s->subtitle_rects[0]->x += x1;
+    s->subtitle_rects[0]->y += y1;
 
     return 1;
 }
@@ -554,7 +554,7 @@  static int dvdsub_decode(AVCodecContext *avctx,
     DVDSubContext *ctx = avctx->priv_data;
     const uint8_t *buf = avpkt->data;
     int buf_size = avpkt->size;
-    AVSubtitle *sub = data;
+    AVFrame *sub = data;
     int appended = 0;
     int is_menu;
 
@@ -586,7 +586,7 @@  static int dvdsub_decode(AVCodecContext *avctx,
     if (!is_menu && find_smallest_bounding_rectangle(ctx, sub) == 0)
         goto no_subtitle;
 
-    if (ctx->forced_subs_only && !(sub->rects[0]->flags & AV_SUBTITLE_FLAG_FORCED))
+    if (ctx->forced_subs_only && !(sub->subtitle_rects[0]->flags & AV_SUBTITLE_FLAG_FORCED))
         goto no_subtitle;
 
 #if defined(DEBUG)
@@ -595,10 +595,10 @@  static int dvdsub_decode(AVCodecContext *avctx,
 
     snprintf(ppm_name, sizeof(ppm_name), "/tmp/%05d.ppm", ctx->sub_id++);
     ff_dlog(NULL, "start=%d ms end =%d ms\n",
-            sub->start_display_time,
-            sub->end_display_time);
-    ppm_save(ppm_name, sub->rects[0]->data[0],
-             sub->rects[0]->w, sub->rects[0]->h, (uint32_t*) sub->rects[0]->data[1]);
+            sub->subtitle_start_time,
+            sub->subtitle_end_time);
+    ppm_save(ppm_name, sub->subtitle_rects[0]->data[0],
+             sub->subtitle_rects[0]->w, sub->subtitle_rects[0]->h, (uint32_t*) sub->subtitle_rects[0]->data[1]);
     }
 #endif
 
diff --git a/libavcodec/dvdsubenc.c b/libavcodec/dvdsubenc.c
index ff4fbed39d..53df1251ed 100644
--- a/libavcodec/dvdsubenc.c
+++ b/libavcodec/dvdsubenc.c
@@ -250,12 +250,12 @@  static void copy_rectangle(AVSubtitleRect *dst, AVSubtitleRect *src, int cmap[])
 
 static int encode_dvd_subtitles(AVCodecContext *avctx,
                                 uint8_t *outbuf, int outbuf_size,
-                                const AVSubtitle *h)
+                                const AVFrame *h)
 {
     DVDSubtitleContext *dvdc = avctx->priv_data;
     uint8_t *q, *qq;
     int offset1, offset2;
-    int i, rects = h->num_rects, ret;
+    int i, rects = h->num_subtitle_rects, ret;
     unsigned global_palette_hits[33] = { 0 };
     int cmap[256];
     int out_palette[4];
@@ -265,34 +265,34 @@  static int encode_dvd_subtitles(AVCodecContext *avctx,
     int x2, y2;
     int forced = 0;
 
-    if (rects == 0 || !h->rects)
+    if (rects == 0 || !h->subtitle_rects)
         return AVERROR(EINVAL);
     for (i = 0; i < rects; i++)
-        if (h->rects[i]->type != SUBTITLE_BITMAP) {
+        if (h->subtitle_rects[i]->type != AV_SUBTITLE_FMT_BITMAP) {
             av_log(avctx, AV_LOG_ERROR, "Bitmap subtitle required\n");
             return AVERROR(EINVAL);
         }
     /* Mark this subtitle forced if any of the rectangles is forced. */
     for (i = 0; i < rects; i++)
-        if ((h->rects[i]->flags & AV_SUBTITLE_FLAG_FORCED) != 0) {
+        if ((h->subtitle_rects[i]->flags & AV_SUBTITLE_FLAG_FORCED) != 0) {
             forced = 1;
             break;
         }
 
-    vrect = *h->rects[0];
+    vrect = *h->subtitle_rects[0];
 
     if (rects > 1) {
         /* DVD subtitles can have only one rectangle: build a virtual
            rectangle containing all actual rectangles.
            The data of the rectangles will be copied later, when the palette
            is decided, because the rectangles may have different palettes. */
-        int xmin = h->rects[0]->x, xmax = xmin + h->rects[0]->w;
-        int ymin = h->rects[0]->y, ymax = ymin + h->rects[0]->h;
+        int xmin = h->subtitle_rects[0]->x, xmax = xmin + h->subtitle_rects[0]->w;
+        int ymin = h->subtitle_rects[0]->y, ymax = ymin + h->subtitle_rects[0]->h;
         for (i = 1; i < rects; i++) {
-            xmin = FFMIN(xmin, h->rects[i]->x);
-            ymin = FFMIN(ymin, h->rects[i]->y);
-            xmax = FFMAX(xmax, h->rects[i]->x + h->rects[i]->w);
-            ymax = FFMAX(ymax, h->rects[i]->y + h->rects[i]->h);
+            xmin = FFMIN(xmin, h->subtitle_rects[i]->x);
+            ymin = FFMIN(ymin, h->subtitle_rects[i]->y);
+            xmax = FFMAX(xmax, h->subtitle_rects[i]->x + h->subtitle_rects[i]->w);
+            ymax = FFMAX(ymax, h->subtitle_rects[i]->y + h->subtitle_rects[i]->h);
         }
         vrect.x = xmin;
         vrect.y = ymin;
@@ -304,11 +304,11 @@  static int encode_dvd_subtitles(AVCodecContext *avctx,
         /* Count pixels outside the virtual rectangle as transparent */
         global_palette_hits[0] = vrect.w * vrect.h;
         for (i = 0; i < rects; i++)
-            global_palette_hits[0] -= h->rects[i]->w * h->rects[i]->h;
+            global_palette_hits[0] -= h->subtitle_rects[i]->w * h->subtitle_rects[i]->h;
     }
 
     for (i = 0; i < rects; i++)
-        count_colors(avctx, global_palette_hits, h->rects[i]);
+        count_colors(avctx, global_palette_hits, h->subtitle_rects[i]);
     select_palette(avctx, out_palette, out_alpha, global_palette_hits);
 
     if (rects > 1) {
@@ -317,14 +317,14 @@  static int encode_dvd_subtitles(AVCodecContext *avctx,
         vrect.data    [0] = vrect_data;
         vrect.linesize[0] = vrect.w;
         for (i = 0; i < rects; i++) {
-            build_color_map(avctx, cmap, (uint32_t *)h->rects[i]->data[1],
+            build_color_map(avctx, cmap, (uint32_t *)h->subtitle_rects[i]->data[1],
                             out_palette, out_alpha);
-            copy_rectangle(&vrect, h->rects[i], cmap);
+            copy_rectangle(&vrect, h->subtitle_rects[i], cmap);
         }
         for (i = 0; i < 4; i++)
             cmap[i] = i;
     } else {
-        build_color_map(avctx, cmap, (uint32_t *)h->rects[0]->data[1],
+        build_color_map(avctx, cmap, (uint32_t *)h->subtitle_rects[0]->data[1],
                         out_palette, out_alpha);
     }
 
@@ -362,7 +362,7 @@  static int encode_dvd_subtitles(AVCodecContext *avctx,
     bytestream_put_be16(&qq, q - outbuf);
 
     // send start display command
-    bytestream_put_be16(&q, (h->start_display_time*90) >> 10);
+    bytestream_put_be16(&q, (h->subtitle_start_time*90) >> 10);
     bytestream_put_be16(&q, (q - outbuf) /*- 2 */ + 8 + 12 + 2);
     *q++ = 0x03; // palette - 4 nibbles
     *q++ = (out_palette[3] << 4) | out_palette[2];
@@ -394,7 +394,7 @@  static int encode_dvd_subtitles(AVCodecContext *avctx,
     *q++ = 0xff; // terminating command
 
     // send stop display command last
-    bytestream_put_be16(&q, (h->end_display_time*90) >> 10);
+    bytestream_put_be16(&q, (h->subtitle_end_time*90) >> 10);
     bytestream_put_be16(&q, (q - outbuf) - 2 /*+ 4*/);
     *q++ = 0x02; // set end
     *q++ = 0xff; // terminating command
@@ -469,7 +469,7 @@  static int dvdsub_init(AVCodecContext *avctx)
 
 static int dvdsub_encode(AVCodecContext *avctx,
                          unsigned char *buf, int buf_size,
-                         const AVSubtitle *sub)
+                         const AVFrame *sub)
 {
     //DVDSubtitleContext *s = avctx->priv_data;
     int ret;
diff --git a/libavcodec/encode.c b/libavcodec/encode.c
index 98dfbfdff3..289f6e88f1 100644
--- a/libavcodec/encode.c
+++ b/libavcodec/encode.c
@@ -141,11 +141,11 @@  fail:
 }
 
 int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size,
-                            const AVSubtitle *sub)
+                            const AVFrame *sub)
 {
     int ret;
-    if (sub->start_display_time) {
-        av_log(avctx, AV_LOG_ERROR, "start_display_time must be 0.\n");
+    if (sub->subtitle_start_time) {
+        av_log(avctx, AV_LOG_ERROR, "subtitle_start_time must be 0.\n");
         return -1;
     }
 
diff --git a/libavcodec/jacosubdec.c b/libavcodec/jacosubdec.c
index 698895a86b..4c87d0f06d 100644
--- a/libavcodec/jacosubdec.c
+++ b/libavcodec/jacosubdec.c
@@ -166,7 +166,7 @@  static int jacosub_decode_frame(AVCodecContext *avctx,
                                 void *data, int *got_sub_ptr, AVPacket *avpkt)
 {
     int ret;
-    AVSubtitle *sub = data;
+    AVFrame *sub = data;
     const char *ptr = avpkt->data;
     FFASSDecoderContext *s = avctx->priv_data;
 
@@ -190,7 +190,7 @@  static int jacosub_decode_frame(AVCodecContext *avctx,
     }
 
 end:
-    *got_sub_ptr = sub->num_rects > 0;
+    *got_sub_ptr = sub->num_subtitle_rects > 0;
     return avpkt->size;
 }
 
diff --git a/libavcodec/libzvbi-teletextdec.c b/libavcodec/libzvbi-teletextdec.c
index 1073d6a0bd..b597042c52 100644
--- a/libavcodec/libzvbi-teletextdec.c
+++ b/libavcodec/libzvbi-teletextdec.c
@@ -215,7 +215,7 @@  static int gen_sub_text(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page
     }
 
     if (buf.len) {
-        sub_rect->type = SUBTITLE_ASS;
+        sub_rect->type = AV_SUBTITLE_FMT_ASS;
         sub_rect->ass = create_ass_text(ctx, buf.str);
 
         if (!sub_rect->ass) {
@@ -224,7 +224,7 @@  static int gen_sub_text(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page
         }
         av_log(ctx, AV_LOG_DEBUG, "subtext:%s:txetbus\n", sub_rect->ass);
     } else {
-        sub_rect->type = SUBTITLE_NONE;
+        sub_rect->type = AV_SUBTITLE_FMT_NONE;
     }
     av_bprint_finalize(&buf, NULL);
     return 0;
@@ -393,7 +393,7 @@  static int gen_sub_ass(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page
     }
 
     if (buf.len) {
-        sub_rect->type = SUBTITLE_ASS;
+        sub_rect->type = AV_SUBTITLE_FMT_ASS;
         sub_rect->ass = ff_ass_get_dialog(ctx->readorder++, 0, is_subtitle_page ? "Subtitle" : "Teletext", NULL, buf.str);
 
         if (!sub_rect->ass) {
@@ -402,7 +402,7 @@  static int gen_sub_ass(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page
         }
         av_log(ctx, AV_LOG_DEBUG, "subtext:%s:txetbus\n", sub_rect->ass);
     } else {
-        sub_rect->type = SUBTITLE_NONE;
+        sub_rect->type = AV_SUBTITLE_FMT_NONE;
     }
     av_bprint_finalize(&buf, NULL);
     return 0;
@@ -462,7 +462,7 @@  static int gen_sub_bitmap(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_pa
 
     if (vc >= vcend) {
         av_log(ctx, AV_LOG_DEBUG, "dropping empty page %3x\n", page->pgno);
-        sub_rect->type = SUBTITLE_NONE;
+        sub_rect->type = AV_SUBTITLE_FMT_NONE;
         return 0;
     }
 
@@ -500,7 +500,7 @@  static int gen_sub_bitmap(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_pa
     }
     ((uint32_t *)sub_rect->data[1])[VBI_TRANSPARENT_BLACK] = RGBA(0, 0, 0, 0);
     ((uint32_t *)sub_rect->data[1])[VBI_TRANSPARENT_BLACK + VBI_NB_COLORS] = RGBA(0, 0, 0, 0);
-    sub_rect->type = SUBTITLE_BITMAP;
+    sub_rect->type = AV_SUBTITLE_FMT_BITMAP;
     return 0;
 }
 
@@ -639,7 +639,7 @@  static int slice_to_vbi_lines(TeletextContext *ctx, uint8_t* buf, int size)
 static int teletext_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, AVPacket *pkt)
 {
     TeletextContext *ctx = avctx->priv_data;
-    AVSubtitle      *sub = data;
+    AVFrame      *sub = data;
     int             ret = 0;
 
     if (!ctx->vbi) {
@@ -695,7 +695,7 @@  static int teletext_decode_frame(AVCodecContext *avctx, void *data, int *got_sub
         sub->num_rects = 0;
         sub->pts = ctx->pages->pts;
 
-        if (ctx->pages->sub_rect->type != SUBTITLE_NONE) {
+        if (ctx->pages->sub_rect->type != AV_SUBTITLE_FMT_NONE) {
             sub->rects = av_malloc(sizeof(*sub->rects));
             if (sub->rects) {
                 sub->num_rects = 1;
diff --git a/libavcodec/microdvddec.c b/libavcodec/microdvddec.c
index c45fe043bf..8618c94bf2 100644
--- a/libavcodec/microdvddec.c
+++ b/libavcodec/microdvddec.c
@@ -277,7 +277,7 @@  static void microdvd_close_no_persistent_tags(AVBPrint *new_line,
 static int microdvd_decode_frame(AVCodecContext *avctx,
                                  void *data, int *got_sub_ptr, AVPacket *avpkt)
 {
-    AVSubtitle *sub = data;
+    AVFrame *sub = data;
     AVBPrint new_line;
     char *line = avpkt->data;
     char *end = avpkt->data + avpkt->size;
@@ -316,7 +316,7 @@  static int microdvd_decode_frame(AVCodecContext *avctx,
             return ret;
     }
 
-    *got_sub_ptr = sub->num_rects > 0;
+    *got_sub_ptr = sub->num_subtitle_rects > 0;
     return avpkt->size;
 }
 
diff --git a/libavcodec/movtextdec.c b/libavcodec/movtextdec.c
index 4e14ae5900..55fc1db69d 100644
--- a/libavcodec/movtextdec.c
+++ b/libavcodec/movtextdec.c
@@ -461,7 +461,7 @@  static int mov_text_init(AVCodecContext *avctx) {
 static int mov_text_decode_frame(AVCodecContext *avctx,
                             void *data, int *got_sub_ptr, AVPacket *avpkt)
 {
-    AVSubtitle *sub = data;
+    AVFrame *sub = data;
     MovTextContext *m = avctx->priv_data;
     int ret;
     AVBPrint buf;
@@ -549,7 +549,7 @@  static int mov_text_decode_frame(AVCodecContext *avctx,
     av_bprint_finalize(&buf, NULL);
     if (ret < 0)
         return ret;
-    *got_sub_ptr = sub->num_rects > 0;
+    *got_sub_ptr = sub->num_subtitle_rects > 0;
     return avpkt->size;
 }
 
diff --git a/libavcodec/movtextenc.c b/libavcodec/movtextenc.c
index 2ae5a9bf0b..315fb9732a 100644
--- a/libavcodec/movtextenc.c
+++ b/libavcodec/movtextenc.c
@@ -635,7 +635,7 @@  static const ASSCodesCallbacks mov_text_callbacks = {
 };
 
 static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf,
-                                 int bufsize, const AVSubtitle *sub)
+                                 int bufsize, const AVFrame *sub)
 {
     MovTextContext *s = avctx->priv_data;
     ASSDialog *dialog;
@@ -646,11 +646,11 @@  static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf,
     s->text_pos = 0;
     s->count = 0;
     s->box_flags = 0;
-    for (i = 0; i < sub->num_rects; i++) {
-        const char *ass = sub->rects[i]->ass;
+    for (i = 0; i < sub->num_subtitle_rects; i++) {
+        const char *ass = sub->subtitle_rects[i]->ass;
 
-        if (sub->rects[i]->type != SUBTITLE_ASS) {
-            av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
+        if (sub->subtitle_rects[i]->type != AV_SUBTITLE_FMT_ASS) {
+            av_log(avctx, AV_LOG_ERROR, "Only AV_SUBTITLE_FMT_ASS type supported.\n");
             return AVERROR(EINVAL);
         }
 
diff --git a/libavcodec/mpl2dec.c b/libavcodec/mpl2dec.c
index 61e47050ec..76efc0ce4f 100644
--- a/libavcodec/mpl2dec.c
+++ b/libavcodec/mpl2dec.c
@@ -68,7 +68,7 @@  static int mpl2_decode_frame(AVCodecContext *avctx, void *data,
 {
     int ret = 0;
     AVBPrint buf;
-    AVSubtitle *sub = data;
+    AVFrame *sub = data;
     const char *ptr = avpkt->data;
     FFASSDecoderContext *s = avctx->priv_data;
 
@@ -78,7 +78,7 @@  static int mpl2_decode_frame(AVCodecContext *avctx, void *data,
     av_bprint_finalize(&buf, NULL);
     if (ret < 0)
         return ret;
-    *got_sub_ptr = sub->num_rects > 0;
+    *got_sub_ptr = sub->num_subtitle_rects > 0;
     return avpkt->size;
 }
 
diff --git a/libavcodec/pgssubdec.c b/libavcodec/pgssubdec.c
index 55eda4c2a9..1e4557ed42 100644
--- a/libavcodec/pgssubdec.c
+++ b/libavcodec/pgssubdec.c
@@ -498,28 +498,28 @@  static int parse_presentation_segment(AVCodecContext *avctx,
 static int display_end_segment(AVCodecContext *avctx, void *data,
                                const uint8_t *buf, int buf_size)
 {
-    AVSubtitle    *sub = data;
+    AVFrame    *sub = data;
     PGSSubContext *ctx = avctx->priv_data;
     int64_t pts;
     PGSSubPalette *palette;
     int i, ret;
 
-    pts = ctx->presentation.pts != AV_NOPTS_VALUE ? ctx->presentation.pts : sub->pts;
+    pts = ctx->presentation.pts != AV_NOPTS_VALUE ? ctx->presentation.pts : sub->subtitle_pts;
     memset(sub, 0, sizeof(*sub));
-    sub->pts = pts;
+    sub->subtitle_pts = pts;
     ctx->presentation.pts = AV_NOPTS_VALUE;
-    sub->start_display_time = 0;
+    sub->subtitle_start_time = 0;
     // There is no explicit end time for PGS subtitles.  The end time
     // is defined by the start of the next sub which may contain no
     // objects (i.e. clears the previous sub)
-    sub->end_display_time   = UINT32_MAX;
-    sub->format             = 0;
+    sub->subtitle_end_time   = UINT32_MAX;
+    sub->format             = AV_SUBTITLE_FMT_BITMAP;
 
     // Blank if last object_count was 0.
     if (!ctx->presentation.object_count)
         return 1;
-    sub->rects = av_mallocz_array(ctx->presentation.object_count, sizeof(*sub->rects));
-    if (!sub->rects) {
+    sub->subtitle_rects = av_mallocz_array(ctx->presentation.object_count, sizeof(*sub->subtitle_rects));
+    if (!sub->subtitle_rects) {
         return AVERROR(ENOMEM);
     }
     palette = find_palette(ctx->presentation.palette_id, &ctx->palettes);
@@ -527,19 +527,19 @@  static int display_end_segment(AVCodecContext *avctx, void *data,
         // Missing palette.  Should only happen with damaged streams.
         av_log(avctx, AV_LOG_ERROR, "Invalid palette id %d\n",
                ctx->presentation.palette_id);
-        avsubtitle_free(sub);
+        av_frame_free(&sub);
         return AVERROR_INVALIDDATA;
     }
     for (i = 0; i < ctx->presentation.object_count; i++) {
         PGSSubObject *object;
 
-        sub->rects[i]  = av_mallocz(sizeof(*sub->rects[0]));
-        if (!sub->rects[i]) {
-            avsubtitle_free(sub);
+        sub->subtitle_rects[i]  = av_mallocz(sizeof(*sub->subtitle_rects[0]));
+        if (!sub->subtitle_rects[i]) {
+            av_frame_free(&sub);
             return AVERROR(ENOMEM);
         }
-        sub->num_rects++;
-        sub->rects[i]->type = SUBTITLE_BITMAP;
+        sub->num_subtitle_rects++;
+        sub->subtitle_rects[i]->type = AV_SUBTITLE_FMT_BITMAP;
 
         /* Process bitmap */
         object = find_object(ctx->presentation.objects[i].id, &ctx->objects);
@@ -548,54 +548,54 @@  static int display_end_segment(AVCodecContext *avctx, void *data,
             av_log(avctx, AV_LOG_ERROR, "Invalid object id %d\n",
                    ctx->presentation.objects[i].id);
             if (avctx->err_recognition & AV_EF_EXPLODE) {
-                avsubtitle_free(sub);
+                av_frame_free(&sub);
                 return AVERROR_INVALIDDATA;
             }
             // Leaves rect empty with 0 width and height.
             continue;
         }
         if (ctx->presentation.objects[i].composition_flag & 0x40)
-            sub->rects[i]->flags |= AV_SUBTITLE_FLAG_FORCED;
+            sub->subtitle_rects[i]->flags |= AV_SUBTITLE_FLAG_FORCED;
 
-        sub->rects[i]->x    = ctx->presentation.objects[i].x;
-        sub->rects[i]->y    = ctx->presentation.objects[i].y;
+        sub->subtitle_rects[i]->x    = ctx->presentation.objects[i].x;
+        sub->subtitle_rects[i]->y    = ctx->presentation.objects[i].y;
 
         if (object->rle) {
-            sub->rects[i]->w    = object->w;
-            sub->rects[i]->h    = object->h;
+            sub->subtitle_rects[i]->w    = object->w;
+            sub->subtitle_rects[i]->h    = object->h;
 
-            sub->rects[i]->linesize[0] = object->w;
+            sub->subtitle_rects[i]->linesize[0] = object->w;
 
             if (object->rle_remaining_len) {
                 av_log(avctx, AV_LOG_ERROR, "RLE data length %u is %u bytes shorter than expected\n",
                        object->rle_data_len, object->rle_remaining_len);
                 if (avctx->err_recognition & AV_EF_EXPLODE) {
-                    avsubtitle_free(sub);
+                    av_frame_free(&sub);
                     return AVERROR_INVALIDDATA;
                 }
             }
-            ret = decode_rle(avctx, sub->rects[i], object->rle, object->rle_data_len);
+            ret = decode_rle(avctx, sub->subtitle_rects[i], object->rle, object->rle_data_len);
             if (ret < 0) {
                 if ((avctx->err_recognition & AV_EF_EXPLODE) ||
                     ret == AVERROR(ENOMEM)) {
-                    avsubtitle_free(sub);
+                    av_frame_free(&sub);
                     return ret;
                 }
-                sub->rects[i]->w = 0;
-                sub->rects[i]->h = 0;
+                sub->subtitle_rects[i]->w = 0;
+                sub->subtitle_rects[i]->h = 0;
                 continue;
             }
         }
         /* Allocate memory for colors */
-        sub->rects[i]->nb_colors    = 256;
-        sub->rects[i]->data[1] = av_mallocz(AVPALETTE_SIZE);
-        if (!sub->rects[i]->data[1]) {
-            avsubtitle_free(sub);
+        sub->subtitle_rects[i]->nb_colors    = 256;
+        sub->subtitle_rects[i]->data[1] = av_mallocz(AVPALETTE_SIZE);
+        if (!sub->subtitle_rects[i]->data[1]) {
+            av_frame_free(&sub);
             return AVERROR(ENOMEM);
         }
 
         if (!ctx->forced_subs_only || ctx->presentation.objects[i].composition_flag & 0x40)
-        memcpy(sub->rects[i]->data[1], palette->clut, sub->rects[i]->nb_colors * sizeof(uint32_t));
+        memcpy(sub->subtitle_rects[i]->data[1], palette->clut, sub->subtitle_rects[i]->nb_colors * sizeof(uint32_t));
     }
     return 1;
 }
@@ -605,7 +605,7 @@  static int decode(AVCodecContext *avctx, void *data, int *got_sub_ptr,
 {
     const uint8_t *buf = avpkt->data;
     int buf_size       = avpkt->size;
-
+    AVFrame *sub = data;
     const uint8_t *buf_end;
     uint8_t       segment_type;
     int           segment_length;
@@ -649,7 +649,7 @@  static int decode(AVCodecContext *avctx, void *data, int *got_sub_ptr,
             ret = parse_object_segment(avctx, buf, segment_length);
             break;
         case PRESENTATION_SEGMENT:
-            ret = parse_presentation_segment(avctx, buf, segment_length, ((AVSubtitle*)(data))->pts);
+            ret = parse_presentation_segment(avctx, buf, segment_length, sub->subtitle_pts);
             break;
         case WINDOW_SEGMENT:
             /*
@@ -678,7 +678,7 @@  static int decode(AVCodecContext *avctx, void *data, int *got_sub_ptr,
             break;
         }
         if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) {
-            avsubtitle_free(data);
+            av_frame_free(&sub);
             *got_sub_ptr = 0;
             return ret;
         }
diff --git a/libavcodec/realtextdec.c b/libavcodec/realtextdec.c
index 11b586d493..8ce24e0bcc 100644
--- a/libavcodec/realtextdec.c
+++ b/libavcodec/realtextdec.c
@@ -60,7 +60,7 @@  static int realtext_decode_frame(AVCodecContext *avctx,
                                  void *data, int *got_sub_ptr, AVPacket *avpkt)
 {
     int ret = 0;
-    AVSubtitle *sub = data;
+    AVFrame *sub = data;
     const char *ptr = avpkt->data;
     FFASSDecoderContext *s = avctx->priv_data;
     AVBPrint buf;
@@ -71,7 +71,7 @@  static int realtext_decode_frame(AVCodecContext *avctx,
     av_bprint_finalize(&buf, NULL);
     if (ret < 0)
         return ret;
-    *got_sub_ptr = sub->num_rects > 0;
+    *got_sub_ptr = sub->num_subtitle_rects > 0;
     return avpkt->size;
 }
 
diff --git a/libavcodec/samidec.c b/libavcodec/samidec.c
index 32d07447b4..2c25edefea 100644
--- a/libavcodec/samidec.c
+++ b/libavcodec/samidec.c
@@ -135,7 +135,7 @@  end:
 static int sami_decode_frame(AVCodecContext *avctx,
                              void *data, int *got_sub_ptr, AVPacket *avpkt)
 {
-    AVSubtitle *sub = data;
+    AVFrame *sub = data;
     const char *ptr = avpkt->data;
     SAMIContext *sami = avctx->priv_data;
 
@@ -148,7 +148,7 @@  static int sami_decode_frame(AVCodecContext *avctx,
         if (ret < 0)
             return ret;
     }
-    *got_sub_ptr = sub->num_rects > 0;
+    *got_sub_ptr = sub->num_subtitle_rects > 0;
     return avpkt->size;
 }
 
diff --git a/libavcodec/srtdec.c b/libavcodec/srtdec.c
index 4f16226b83..557ffab45e 100644
--- a/libavcodec/srtdec.c
+++ b/libavcodec/srtdec.c
@@ -56,7 +56,7 @@  static int srt_to_ass(AVCodecContext *avctx, AVBPrint *dst,
 static int srt_decode_frame(AVCodecContext *avctx,
                             void *data, int *got_sub_ptr, AVPacket *avpkt)
 {
-    AVSubtitle *sub = data;
+    AVFrame *sub = data;
     AVBPrint buffer;
     int x1 = -1, y1 = -1, x2 = -1, y2 = -1;
     int ret;
@@ -83,7 +83,7 @@  static int srt_decode_frame(AVCodecContext *avctx,
     if (ret < 0)
         return ret;
 
-    *got_sub_ptr = sub->num_rects > 0;
+    *got_sub_ptr = sub->num_subtitle_rects > 0;
     return avpkt->size;
 }
 
diff --git a/libavcodec/srtenc.c b/libavcodec/srtenc.c
index 2e3ac55770..f4a9de1e70 100644
--- a/libavcodec/srtenc.c
+++ b/libavcodec/srtenc.c
@@ -228,7 +228,7 @@  static const ASSCodesCallbacks text_callbacks = {
 };
 
 static int encode_frame(AVCodecContext *avctx,
-                        unsigned char *buf, int bufsize, const AVSubtitle *sub,
+                        unsigned char *buf, int bufsize, const AVFrame *sub,
                         const ASSCodesCallbacks *cb)
 {
     SRTContext *s = avctx->priv_data;
@@ -237,11 +237,11 @@  static int encode_frame(AVCodecContext *avctx,
 
     av_bprint_clear(&s->buffer);
 
-    for (i=0; i<sub->num_rects; i++) {
-        const char *ass = sub->rects[i]->ass;
+    for (i=0; i<sub->num_subtitle_rects; i++) {
+        const char *ass = sub->subtitle_rects[i]->ass;
 
-        if (sub->rects[i]->type != SUBTITLE_ASS) {
-            av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
+        if (sub->subtitle_rects[i]->type != AV_SUBTITLE_FMT_ASS) {
+            av_log(avctx, AV_LOG_ERROR, "Only AV_SUBTITLE_FMT_ASS type supported.\n");
             return AVERROR(EINVAL);
         }
 
@@ -270,13 +270,13 @@  static int encode_frame(AVCodecContext *avctx,
 }
 
 static int srt_encode_frame(AVCodecContext *avctx,
-                               unsigned char *buf, int bufsize, const AVSubtitle *sub)
+                               unsigned char *buf, int bufsize, const AVFrame *sub)
 {
     return encode_frame(avctx, buf, bufsize, sub, &srt_callbacks);
 }
 
 static int text_encode_frame(AVCodecContext *avctx,
-                             unsigned char *buf, int bufsize, const AVSubtitle *sub)
+                             unsigned char *buf, int bufsize, const AVFrame *sub)
 {
     return encode_frame(avctx, buf, bufsize, sub, &text_callbacks);
 }
diff --git a/libavcodec/subviewerdec.c b/libavcodec/subviewerdec.c
index 5c650d0cde..e4eff51d33 100644
--- a/libavcodec/subviewerdec.c
+++ b/libavcodec/subviewerdec.c
@@ -51,7 +51,7 @@  static int subviewer_decode_frame(AVCodecContext *avctx,
                                   void *data, int *got_sub_ptr, AVPacket *avpkt)
 {
     int ret = 0;
-    AVSubtitle *sub = data;
+    AVFrame *sub = data;
     const char *ptr = avpkt->data;
     FFASSDecoderContext *s = avctx->priv_data;
     AVBPrint buf;
@@ -62,7 +62,7 @@  static int subviewer_decode_frame(AVCodecContext *avctx,
     av_bprint_finalize(&buf, NULL);
     if (ret < 0)
         return ret;
-    *got_sub_ptr = sub->num_rects > 0;
+    *got_sub_ptr = sub->num_subtitle_rects > 0;
     return avpkt->size;
 }
 
diff --git a/libavcodec/textdec.c b/libavcodec/textdec.c
index 308553660a..274b53f74d 100644
--- a/libavcodec/textdec.c
+++ b/libavcodec/textdec.c
@@ -48,7 +48,7 @@  static int text_decode_frame(AVCodecContext *avctx, void *data,
 {
     int ret = 0;
     AVBPrint buf;
-    AVSubtitle *sub = data;
+    AVFrame *sub = data;
     const char *ptr = avpkt->data;
     TextContext *text = avctx->priv_data;
 
@@ -60,7 +60,7 @@  static int text_decode_frame(AVCodecContext *avctx, void *data,
     av_bprint_finalize(&buf, NULL);
     if (ret < 0)
         return ret;
-    *got_sub_ptr = sub->num_rects > 0;
+    *got_sub_ptr = sub->num_subtitle_rects > 0;
     return avpkt->size;
 }
 
diff --git a/libavcodec/ttmlenc.c b/libavcodec/ttmlenc.c
index ad2eddfdd5..3a439db98e 100644
--- a/libavcodec/ttmlenc.c
+++ b/libavcodec/ttmlenc.c
@@ -78,7 +78,7 @@  static const ASSCodesCallbacks ttml_callbacks = {
 };
 
 static int ttml_encode_frame(AVCodecContext *avctx, uint8_t *buf,
-                             int bufsize, const AVSubtitle *sub)
+                             int bufsize, const AVFrame *sub)
 {
     TTMLContext *s = avctx->priv_data;
     ASSDialog *dialog;
@@ -86,12 +86,12 @@  static int ttml_encode_frame(AVCodecContext *avctx, uint8_t *buf,
 
     av_bprint_clear(&s->buffer);
 
-    for (i=0; i<sub->num_rects; i++) {
-        const char *ass = sub->rects[i]->ass;
+    for (i=0; i<sub->num_subtitle_rects; i++) {
+        const char *ass = sub->subtitle_rects[i]->ass;
         int ret;
 
-        if (sub->rects[i]->type != SUBTITLE_ASS) {
-            av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
+        if (sub->subtitle_rects[i]->type != AV_SUBTITLE_FMT_ASS) {
+            av_log(avctx, AV_LOG_ERROR, "Only AV_SUBTITLE_FMT_ASS type supported.\n");
             return AVERROR(EINVAL);
         }
 
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index cfc07cbcb8..767dfabd1e 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -818,6 +818,17 @@  int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes)
     return FFMAX(0, duration);
 }
 
+enum AVSubtitleType av_get_subtitle_format_from_codecdesc(const AVCodecDescriptor *codec_descriptor)
+{
+    if(codec_descriptor->props & AV_CODEC_PROP_BITMAP_SUB)
+        return AV_SUBTITLE_FMT_BITMAP;
+
+    if(codec_descriptor->props & AV_CODEC_PROP_TEXT_SUB)
+        return AV_SUBTITLE_FMT_ASS;
+
+    return AV_SUBTITLE_FMT_UNKNOWN;
+}
+
 int av_get_audio_frame_duration2(AVCodecParameters *par, int frame_bytes)
 {
     int duration = get_audio_frame_duration(par->codec_id, par->sample_rate,
diff --git a/libavcodec/webvttdec.c b/libavcodec/webvttdec.c
index 0093f328fa..23b0c5245c 100644
--- a/libavcodec/webvttdec.c
+++ b/libavcodec/webvttdec.c
@@ -84,7 +84,7 @@  static int webvtt_decode_frame(AVCodecContext *avctx,
                                void *data, int *got_sub_ptr, AVPacket *avpkt)
 {
     int ret = 0;
-    AVSubtitle *sub = data;
+    AVFrame *sub = data;
     const char *ptr = avpkt->data;
     FFASSDecoderContext *s = avctx->priv_data;
     AVBPrint buf;
@@ -95,7 +95,7 @@  static int webvtt_decode_frame(AVCodecContext *avctx,
     av_bprint_finalize(&buf, NULL);
     if (ret < 0)
         return ret;
-    *got_sub_ptr = sub->num_rects > 0;
+    *got_sub_ptr = sub->num_subtitle_rects > 0;
     return avpkt->size;
 }
 
diff --git a/libavcodec/webvttenc.c b/libavcodec/webvttenc.c
index 89b49e42bf..287a246156 100644
--- a/libavcodec/webvttenc.c
+++ b/libavcodec/webvttenc.c
@@ -156,7 +156,7 @@  static const ASSCodesCallbacks webvtt_callbacks = {
 };
 
 static int webvtt_encode_frame(AVCodecContext *avctx,
-                               unsigned char *buf, int bufsize, const AVSubtitle *sub)
+                               unsigned char *buf, int bufsize, const AVFrame *sub)
 {
     WebVTTContext *s = avctx->priv_data;
     ASSDialog *dialog;
@@ -164,11 +164,11 @@  static int webvtt_encode_frame(AVCodecContext *avctx,
 
     av_bprint_clear(&s->buffer);
 
-    for (i=0; i<sub->num_rects; i++) {
-        const char *ass = sub->rects[i]->ass;
+    for (i=0; i<sub->num_subtitle_rects; i++) {
+        const char *ass = sub->subtitle_rects[i]->ass;
 
-        if (sub->rects[i]->type != SUBTITLE_ASS) {
-            av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
+        if (sub->subtitle_rects[i]->type != AV_SUBTITLE_FMT_ASS) {
+            av_log(avctx, AV_LOG_ERROR, "Only AV_SUBTITLE_FMT_ASS type supported.\n");
             return AVERROR(EINVAL);
         }
 
diff --git a/libavcodec/xsubdec.c b/libavcodec/xsubdec.c
index 979399bae6..f45edcc0ca 100644
--- a/libavcodec/xsubdec.c
+++ b/libavcodec/xsubdec.c
@@ -51,7 +51,7 @@  static int decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr,
                         AVPacket *avpkt) {
     const uint8_t *buf = avpkt->data;
     int buf_size = avpkt->size;
-    AVSubtitle *sub = data;
+    AVFrame *sub = data;
     const uint8_t *buf_end = buf + buf_size;
     uint8_t *bitmap;
     int w, h, x, y, i, ret;
@@ -72,8 +72,8 @@  static int decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr,
     }
     if (avpkt->pts != AV_NOPTS_VALUE)
         packet_time = av_rescale_q(avpkt->pts, AV_TIME_BASE_Q, (AVRational){1, 1000});
-    sub->start_display_time = parse_timecode(buf +  1, packet_time);
-    sub->end_display_time   = parse_timecode(buf + 14, packet_time);
+    sub->subtitle_start_time = parse_timecode(buf +  1, packet_time);
+    sub->subtitle_end_time   = parse_timecode(buf + 14, packet_time);
     buf += 27;
 
     // read header
@@ -96,51 +96,51 @@  static int decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr,
         return AVERROR_INVALIDDATA;
 
     // allocate sub and set values
-    sub->rects =  av_mallocz(sizeof(*sub->rects));
-    if (!sub->rects)
+    sub->subtitle_rects =  av_mallocz(sizeof(*sub->subtitle_rects));
+    if (!sub->subtitle_rects)
         return AVERROR(ENOMEM);
 
-    sub->rects[0] = av_mallocz(sizeof(*sub->rects[0]));
-    if (!sub->rects[0]) {
-        av_freep(&sub->rects);
+    sub->subtitle_rects[0] = av_mallocz(sizeof(*sub->subtitle_rects[0]));
+    if (!sub->subtitle_rects[0]) {
+        av_freep(&sub->subtitle_rects);
         return AVERROR(ENOMEM);
     }
-    sub->rects[0]->x = x; sub->rects[0]->y = y;
-    sub->rects[0]->w = w; sub->rects[0]->h = h;
-    sub->rects[0]->type = SUBTITLE_BITMAP;
-    sub->rects[0]->linesize[0] = w;
-    sub->rects[0]->data[0] = av_malloc(w * h);
-    sub->rects[0]->nb_colors = 4;
-    sub->rects[0]->data[1] = av_mallocz(AVPALETTE_SIZE);
-    if (!sub->rects[0]->data[0] || !sub->rects[0]->data[1]) {
-        av_freep(&sub->rects[0]->data[1]);
-        av_freep(&sub->rects[0]->data[0]);
-        av_freep(&sub->rects[0]);
-        av_freep(&sub->rects);
+    sub->subtitle_rects[0]->x = x; sub->subtitle_rects[0]->y = y;
+    sub->subtitle_rects[0]->w = w; sub->subtitle_rects[0]->h = h;
+    sub->subtitle_rects[0]->type = AV_SUBTITLE_FMT_BITMAP;
+    sub->subtitle_rects[0]->linesize[0] = w;
+    sub->subtitle_rects[0]->data[0] = av_malloc(w * h);
+    sub->subtitle_rects[0]->nb_colors = 4;
+    sub->subtitle_rects[0]->data[1] = av_mallocz(AVPALETTE_SIZE);
+    if (!sub->subtitle_rects[0]->data[0] || !sub->subtitle_rects[0]->data[1]) {
+        av_freep(&sub->subtitle_rects[0]->data[1]);
+        av_freep(&sub->subtitle_rects[0]->data[0]);
+        av_freep(&sub->subtitle_rects[0]);
+        av_freep(&sub->subtitle_rects);
         return AVERROR(ENOMEM);
     }
-    sub->num_rects = 1;
+    sub->num_subtitle_rects = 1;
 
     // read palette
-    for (i = 0; i < sub->rects[0]->nb_colors; i++)
-        ((uint32_t*)sub->rects[0]->data[1])[i] = bytestream_get_be24(&buf);
+    for (i = 0; i < sub->subtitle_rects[0]->nb_colors; i++)
+        ((uint32_t*)sub->subtitle_rects[0]->data[1])[i] = bytestream_get_be24(&buf);
 
     if (!has_alpha) {
         // make all except background (first entry) non-transparent
-        for (i = 1; i < sub->rects[0]->nb_colors; i++)
-            ((uint32_t *)sub->rects[0]->data[1])[i] |= 0xff000000;
+        for (i = 1; i < sub->subtitle_rects[0]->nb_colors; i++)
+            ((uint32_t *)sub->subtitle_rects[0]->data[1])[i] |= 0xff000000;
     } else {
-        for (i = 0; i < sub->rects[0]->nb_colors; i++)
-            ((uint32_t *)sub->rects[0]->data[1])[i] |= (unsigned)*buf++ << 24;
+        for (i = 0; i < sub->subtitle_rects[0]->nb_colors; i++)
+            ((uint32_t *)sub->subtitle_rects[0]->data[1])[i] |= (unsigned)*buf++ << 24;
     }
 
     // process RLE-compressed data
     if ((ret = init_get_bits8(&gb, buf, buf_end - buf)) < 0)
         return ret;
-    bitmap = sub->rects[0]->data[0];
+    bitmap = sub->subtitle_rects[0]->data[0];
     for (y = 0; y < h; y++) {
         // interlaced: do odd lines
-        if (y == (h + 1) / 2) bitmap = sub->rects[0]->data[0] + w;
+        if (y == (h + 1) / 2) bitmap = sub->subtitle_rects[0]->data[0] + w;
         for (x = 0; x < w; ) {
             int log2 = ff_log2_tab[show_bits(&gb, 8)];
             int run = get_bits(&gb, 14 - 4 * (log2 >> 1));
diff --git a/libavcodec/xsubenc.c b/libavcodec/xsubenc.c
index 03d0dc2d86..6508af9a73 100644
--- a/libavcodec/xsubenc.c
+++ b/libavcodec/xsubenc.c
@@ -112,10 +112,10 @@  static int make_tc(uint64_t ms, int *tc)
 }
 
 static int xsub_encode(AVCodecContext *avctx, unsigned char *buf,
-                       int bufsize, const AVSubtitle *h)
+                       int bufsize, const AVFrame *h)
 {
-    uint64_t startTime = h->pts / 1000; // FIXME: need better solution...
-    uint64_t endTime = startTime + h->end_display_time - h->start_display_time;
+    uint64_t startTime = h->subtitle_pts / 1000; // FIXME: need better solution...
+    uint64_t endTime = startTime + h->subtitle_end_time - h->subtitle_start_time;
     int start_tc[4], end_tc[4];
     uint8_t *hdr = buf + 27; // Point behind the timestamp
     uint8_t *rlelenptr;
@@ -129,21 +129,21 @@  static int xsub_encode(AVCodecContext *avctx, unsigned char *buf,
     }
 
     // TODO: support multiple rects
-    if (h->num_rects != 1)
-        av_log(avctx, AV_LOG_WARNING, "Only single rects supported (%d in subtitle.)\n", h->num_rects);
+    if (h->num_subtitle_rects != 1)
+        av_log(avctx, AV_LOG_WARNING, "Only single rects supported (%d in subtitle.)\n", h->num_subtitle_rects);
 
     // TODO: render text-based subtitles into bitmaps
-    if (!h->rects[0]->data[0] || !h->rects[0]->data[1]) {
+    if (!h->subtitle_rects[0]->data[0] || !h->subtitle_rects[0]->data[1]) {
         av_log(avctx, AV_LOG_WARNING, "No subtitle bitmap available.\n");
         return AVERROR(EINVAL);
     }
 
     // TODO: color reduction, similar to dvdsub encoder
-    if (h->rects[0]->nb_colors > 4)
-        av_log(avctx, AV_LOG_WARNING, "No more than 4 subtitle colors supported (%d found.)\n", h->rects[0]->nb_colors);
+    if (h->subtitle_rects[0]->nb_colors > 4)
+        av_log(avctx, AV_LOG_WARNING, "No more than 4 subtitle colors supported (%d found.)\n", h->subtitle_rects[0]->nb_colors);
 
     // TODO: Palette swapping if color zero is not transparent
-    if (((uint32_t *)h->rects[0]->data[1])[0] & 0xff000000)
+    if (((uint32_t *)h->subtitle_rects[0]->data[1])[0] & 0xff000000)
         av_log(avctx, AV_LOG_WARNING, "Color index 0 is not transparent. Transparency will be messed up.\n");
 
     if (make_tc(startTime, start_tc) || make_tc(endTime, end_tc)) {
@@ -160,40 +160,40 @@  static int xsub_encode(AVCodecContext *avctx, unsigned char *buf,
     // 2 pixels required on either side of subtitle.
     // Possibly due to limitations of hardware renderers.
     // TODO: check if the bitmap is already padded
-    width  = FFALIGN(h->rects[0]->w, 2) + PADDING * 2;
-    height = FFALIGN(h->rects[0]->h, 2);
+    width  = FFALIGN(h->subtitle_rects[0]->w, 2) + PADDING * 2;
+    height = FFALIGN(h->subtitle_rects[0]->h, 2);
 
     bytestream_put_le16(&hdr, width);
     bytestream_put_le16(&hdr, height);
-    bytestream_put_le16(&hdr, h->rects[0]->x);
-    bytestream_put_le16(&hdr, h->rects[0]->y);
-    bytestream_put_le16(&hdr, h->rects[0]->x + width -1);
-    bytestream_put_le16(&hdr, h->rects[0]->y + height -1);
+    bytestream_put_le16(&hdr, h->subtitle_rects[0]->x);
+    bytestream_put_le16(&hdr, h->subtitle_rects[0]->y);
+    bytestream_put_le16(&hdr, h->subtitle_rects[0]->x + width -1);
+    bytestream_put_le16(&hdr, h->subtitle_rects[0]->y + height -1);
 
     rlelenptr = hdr; // Will store length of first field here later.
     hdr+=2;
 
     // Palette
     for (i=0; i<4; i++)
-        bytestream_put_be24(&hdr, ((uint32_t *)h->rects[0]->data[1])[i]);
+        bytestream_put_be24(&hdr, ((uint32_t *)h->subtitle_rects[0]->data[1])[i]);
 
     // Bitmap
     // RLE buffer. Reserve 2 bytes for possible padding after the last row.
     init_put_bits(&pb, hdr, bufsize - (hdr - buf) - 2);
-    if (xsub_encode_rle(&pb, h->rects[0]->data[0],
-                        h->rects[0]->linesize[0] * 2,
-                        h->rects[0]->w, (h->rects[0]->h + 1) >> 1))
+    if (xsub_encode_rle(&pb, h->subtitle_rects[0]->data[0],
+                        h->subtitle_rects[0]->linesize[0] * 2,
+                        h->subtitle_rects[0]->w, (h->subtitle_rects[0]->h + 1) >> 1))
         return AVERROR_BUFFER_TOO_SMALL;
     bytestream_put_le16(&rlelenptr, put_bytes_count(&pb, 0)); // Length of first field
 
-    if (xsub_encode_rle(&pb, h->rects[0]->data[0] + h->rects[0]->linesize[0],
-                        h->rects[0]->linesize[0] * 2,
-                        h->rects[0]->w, h->rects[0]->h >> 1))
+    if (xsub_encode_rle(&pb, h->subtitle_rects[0]->data[0] + h->subtitle_rects[0]->linesize[0],
+                        h->subtitle_rects[0]->linesize[0] * 2,
+                        h->subtitle_rects[0]->w, h->subtitle_rects[0]->h >> 1))
         return AVERROR_BUFFER_TOO_SMALL;
 
     // Enforce total height to be a multiple of 2
-    if (h->rects[0]->h & 1) {
-        put_xsub_rle(&pb, h->rects[0]->w, PADDING_COLOR);
+    if (h->subtitle_rects[0]->h & 1) {
+        put_xsub_rle(&pb, h->subtitle_rects[0]->w, PADDING_COLOR);
     }
 
     flush_put_bits(&pb);
diff --git a/libavfilter/vf_subtitles.c b/libavfilter/vf_subtitles.c
index d0bafcd3cf..c536854c45 100644
--- a/libavfilter/vf_subtitles.c
+++ b/libavfilter/vf_subtitles.c
@@ -35,14 +35,12 @@ 
 # include "libavformat/avformat.h"
 #endif
 #include "libavutil/avstring.h"
-#include "libavutil/imgutils.h"
 #include "libavutil/opt.h"
 #include "libavutil/parseutils.h"
 #include "drawutils.h"
 #include "avfilter.h"
 #include "internal.h"
 #include "formats.h"
-#include "video.h"
 
 typedef struct AssContext {
     const AVClass *class;
@@ -306,6 +304,7 @@  static av_cold int init_subtitles(AVFilterContext *ctx)
     AVStream *st;
     AVPacket pkt;
     AssContext *ass = ctx->priv;
+    enum AVSubtitleType subtitle_format;
 
     /* Init libass */
     ret = init(ctx);
@@ -386,16 +385,19 @@  static av_cold int init_subtitles(AVFilterContext *ctx)
         ret = AVERROR_DECODER_NOT_FOUND;
         goto end;
     }
+
     dec_desc = avcodec_descriptor_get(st->codecpar->codec_id);
-    if (dec_desc && !(dec_desc->props & AV_CODEC_PROP_TEXT_SUB)) {
+    subtitle_format = av_get_subtitle_format_from_codecdesc(dec_desc);
+
+    if (subtitle_format != AV_SUBTITLE_FMT_ASS) {
         av_log(ctx, AV_LOG_ERROR,
-               "Only text based subtitles are currently supported\n");
-        ret = AVERROR_PATCHWELCOME;
+               "Only text based subtitles are supported by this filter\n");
+        ret = AVERROR_INVALIDDATA;
         goto end;
     }
+
     if (ass->charenc)
         av_dict_set(&codec_opts, "sub_charenc", ass->charenc, 0);
-    av_dict_set(&codec_opts, "sub_text_format", "ass", 0);
 
     dec_ctx = avcodec_alloc_context3(dec);
     if (!dec_ctx) {
@@ -449,18 +451,18 @@  static av_cold int init_subtitles(AVFilterContext *ctx)
                                   dec_ctx->subtitle_header_size);
     while (av_read_frame(fmt, &pkt) >= 0) {
         int i, got_subtitle;
-        AVSubtitle sub = {0};
+        AVFrame *sub = av_frame_alloc();
 
         if (pkt.stream_index == sid) {
-            ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_subtitle, &pkt);
+            ret = avcodec_decode_subtitle2(dec_ctx, sub, &got_subtitle, &pkt);
             if (ret < 0) {
                 av_log(ctx, AV_LOG_WARNING, "Error decoding: %s (ignored)\n",
                        av_err2str(ret));
             } else if (got_subtitle) {
-                const int64_t start_time = av_rescale_q(sub.pts, AV_TIME_BASE_Q, av_make_q(1, 1000));
-                const int64_t duration   = sub.end_display_time;
-                for (i = 0; i < sub.num_rects; i++) {
-                    char *ass_line = sub.rects[i]->ass;
+                const int64_t start_time = av_rescale_q(sub->subtitle_pts, AV_TIME_BASE_Q, av_make_q(1, 1000));
+                const int64_t duration   = sub->subtitle_end_time;
+                for (i = 0; i < sub->num_subtitle_rects; i++) {
+                    char *ass_line = sub->subtitle_rects[i]->ass;
                     if (!ass_line)
                         break;
                     ass_process_chunk(ass->track, ass_line, strlen(ass_line),
@@ -469,7 +471,7 @@  static av_cold int init_subtitles(AVFilterContext *ctx)
             }
         }
         av_packet_unref(&pkt);
-        avsubtitle_free(&sub);
+        av_frame_free(&sub);
     }
 
 end:
diff --git a/libavformat/utils.c b/libavformat/utils.c
index b56190d2da..f83dadd477 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -2949,7 +2949,6 @@  static int try_decode_frame(AVFormatContext *s, AVStream *st,
     const AVCodec *codec;
     int got_picture = 1, ret = 0;
     AVFrame *frame = av_frame_alloc();
-    AVSubtitle subtitle;
     AVPacket pkt = *avpkt;
     int do_skip_frame = 0;
     enum AVDiscard skip_frame;
@@ -3020,10 +3019,8 @@  static int try_decode_frame(AVFormatContext *s, AVStream *st,
             if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
                 ret = 0;
         } else if (avctx->codec_type == AVMEDIA_TYPE_SUBTITLE) {
-            ret = avcodec_decode_subtitle2(avctx, &subtitle,
+            ret = avcodec_decode_subtitle2(avctx, frame,
                                            &got_picture, &pkt);
-            if (got_picture)
-                avsubtitle_free(&subtitle);
             if (ret >= 0)
                 pkt.size = 0;
         }
diff --git a/libavutil/Makefile b/libavutil/Makefile
index 410ac636f7..04e1101bf3 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -74,6 +74,7 @@  HEADERS = adler32.h                                                     \
           sha512.h                                                      \
           spherical.h                                                   \
           stereo3d.h                                                    \
+          subfmt.h                                                      \
           threadmessage.h                                               \
           time.h                                                        \
           timecode.h                                                    \
@@ -159,6 +160,7 @@  OBJS = adler32.o                                                        \
        slicethread.o                                                    \
        spherical.o                                                      \
        stereo3d.o                                                       \
+       subfmt.o                                                         \
        threadmessage.o                                                  \
        time.o                                                           \
        timecode.o                                                       \
diff --git a/libavutil/frame.c b/libavutil/frame.c
index ef2867d318..1855de9b3d 100644
--- a/libavutil/frame.c
+++ b/libavutil/frame.c
@@ -72,7 +72,12 @@  static void get_frame_defaults(AVFrame *frame)
     frame->colorspace          = AVCOL_SPC_UNSPECIFIED;
     frame->color_range         = AVCOL_RANGE_UNSPECIFIED;
     frame->chroma_location     = AVCHROMA_LOC_UNSPECIFIED;
-    frame->flags               = 0;
+    frame->subtitle_start_time = 0;
+    frame->subtitle_end_time   = 0;
+    frame->num_subtitle_rects  = 0;
+    frame->subtitle_rects      = NULL;
+    frame->subtitle_pts        = 0;
+    frame->subtitle_header     = NULL;
 }
 
 static void free_side_data(AVFrameSideData **ptr_sd)
@@ -306,6 +311,9 @@  static int frame_copy_props(AVFrame *dst, const AVFrame *src, int force_copy)
     dst->colorspace             = src->colorspace;
     dst->color_range            = src->color_range;
     dst->chroma_location        = src->chroma_location;
+    dst->subtitle_start_time    = src->subtitle_start_time;
+    dst->subtitle_end_time      = src->subtitle_end_time;
+    dst->subtitle_pts           = src->subtitle_pts;
 
     av_dict_copy(&dst->metadata, src->metadata, 0);
 
@@ -359,6 +367,19 @@  int av_frame_ref(AVFrame *dst, const AVFrame *src)
     if (ret < 0)
         goto fail;
 
+    /* duplicate subtitle rects */
+    dst->num_subtitle_rects = src->num_subtitle_rects;
+
+    if (src->num_subtitle_rects) {
+        dst->subtitle_rects = av_malloc_array(src->num_subtitle_rects, sizeof(AVSubtitleRect *));
+
+        for (i = 0; i < src->num_subtitle_rects; i++) {
+            AVSubtitleRect *rect = src->subtitle_rects[i];
+            rect->nb_refs++;
+            dst->subtitle_rects[i] = rect;
+        }
+    }
+
     /* duplicate the frame data if it's not refcounted */
     if (!src->buf[0]) {
         ret = av_frame_get_buffer2(dst, 0);
@@ -472,6 +493,24 @@  void av_frame_unref(AVFrame *frame)
     av_buffer_unref(&frame->opaque_ref);
     av_buffer_unref(&frame->private_ref);
 
+    for (i = 0; i < frame->num_subtitle_rects; i++) {
+        AVSubtitleRect *rect = frame->subtitle_rects[i];
+
+        if (rect && rect->nb_refs > 0)
+            rect->nb_refs--;
+        else {
+            av_freep(&rect->data[0]);
+            av_freep(&rect->data[1]);
+            av_freep(&rect->data[2]);
+            av_freep(&rect->data[3]);
+            av_freep(&rect->text);
+            av_freep(&rect->ass);
+            av_freep(&rect);
+        }
+    }
+
+    av_freep(&frame->subtitle_rects);
+
     get_frame_defaults(frame);
 }
 
diff --git a/libavutil/frame.h b/libavutil/frame.h
index 005eed9d18..4e2cfe19b3 100644
--- a/libavutil/frame.h
+++ b/libavutil/frame.h
@@ -34,6 +34,7 @@ 
 #include "rational.h"
 #include "samplefmt.h"
 #include "pixfmt.h"
+#include "subfmt.h"
 #include "version.h"
 
 
@@ -469,6 +470,17 @@  typedef struct AVFrame {
      */
     uint64_t channel_layout;
 
+    uint32_t subtitle_start_time; /* display start time, relative to packet pts, in ms */
+    uint32_t subtitle_end_time; /* display end time, relative to packet pts, in ms */
+    unsigned num_subtitle_rects;
+    AVSubtitleRect **subtitle_rects;
+    int64_t subtitle_pts;    ///< Same as packet pts, in AV_TIME_BASE
+
+    /**
+     * Header containing style information for text subtitles.
+     */
+    char *subtitle_header;
+
     /**
      * AVBuffer references backing the data for this frame. If all elements of
      * this array are NULL, then this frame is not reference counted. This array
diff --git a/libavutil/subfmt.c b/libavutil/subfmt.c
new file mode 100644
index 0000000000..9a19d01aa3
--- /dev/null
+++ b/libavutil/subfmt.c
@@ -0,0 +1,52 @@ 
+/*
+ * Copyright (c) 2021 softworkz
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <string.h>
+#include "common.h"
+#include "subfmt.h"
+
+typedef struct SubtitleFmtInfo {
+    enum AVSubtitleType fmt;
+    char* name;
+} SubtitleFmtInfo;
+
+static SubtitleFmtInfo sub_fmt_info[AV_SUBTITLE_FMT_NB] = {
+    {.fmt = AV_SUBTITLE_FMT_UNKNOWN, .name = "Unknown subtitle format", },
+    {.fmt = AV_SUBTITLE_FMT_BITMAP,  .name = "Graphical subtitles",     },
+    {.fmt = AV_SUBTITLE_FMT_TEXT,    .name = "Text subtitles (plain)",  },
+    {.fmt = AV_SUBTITLE_FMT_ASS,     .name = "Text subtitles (ass)",    },
+};
+
+const char *av_get_subtitle_fmt_name(enum AVSubtitleType sub_fmt)
+{
+    if (sub_fmt < 0 || sub_fmt >= AV_SUBTITLE_FMT_NB)
+        return NULL;
+    return sub_fmt_info[sub_fmt].name;
+}
+
+enum AVSubtitleType av_get_subtitle_fmt(const char *name)
+{
+    int i;
+
+    for (i = 0; i < AV_SUBTITLE_FMT_NB; i++)
+        if (!strcmp(sub_fmt_info[i].name, name))
+            return i;
+    return AV_SUBTITLE_FMT_NONE;
+}
diff --git a/libavutil/subfmt.h b/libavutil/subfmt.h
new file mode 100644
index 0000000000..31dabc957c
--- /dev/null
+++ b/libavutil/subfmt.h
@@ -0,0 +1,94 @@ 
+/*
+ * Copyright (c) 2021 softworkz
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_SUBFMT_H
+#define AVUTIL_SUBFMT_H
+
+#include <inttypes.h>
+
+enum AVSubtitleType {
+
+    /**
+     * Subtitle format unknown.
+     */
+    AV_SUBTITLE_FMT_NONE = -1,
+
+    /**
+     * Subtitle format unknown.
+     */
+    AV_SUBTITLE_FMT_UNKNOWN = 0,
+
+    /**
+     * Bitmap area in AVSubtitleRect.data, pixfmt AV_PIX_FMT_PAL8.
+     */
+    AV_SUBTITLE_FMT_BITMAP = 1,
+
+    /**
+     * Plain text in AVSubtitleRect.text.
+     */
+    AV_SUBTITLE_FMT_TEXT = 2,
+
+    /**
+     * Text Formatted as per ASS specification, contained AVSubtitleRect.ass.
+     */
+    AV_SUBTITLE_FMT_ASS = 3,
+
+    AV_SUBTITLE_FMT_NB,
+};
+
+typedef struct AVSubtitleRect {
+    unsigned nb_refs;
+    int x;         ///< top left corner  of pict, undefined when pict is not set
+    int y;         ///< top left corner  of pict, undefined when pict is not set
+    int w;         ///< width            of pict, undefined when pict is not set
+    int h;         ///< height           of pict, undefined when pict is not set
+    int nb_colors; ///< number of colors in pict, undefined when pict is not set
+
+    /**
+     * data+linesize for the bitmap of this subtitle.
+     */
+    uint8_t *data[4];
+    int linesize[4];
+
+    enum AVSubtitleType type;
+
+    char *text;                     ///< 0 terminated plain UTF-8 text
+
+    /**
+     * 0-terminated ASS/SSA compatible event line.
+     */
+    char *ass;
+
+    int flags;
+} AVSubtitleRect;
+
+/**
+ * Return the name of sub_fmt, or NULL if sub_fmt is not
+ * recognized.
+ */
+const char *av_get_subtitle_fmt_name(enum AVSubtitleType sub_fmt);
+
+/**
+ * Return a subtitle format corresponding to name, or AV_SUBTITLE_FMT_NONE
+ * on error.
+ */
+enum AVSubtitleType av_get_subtitle_fmt(const char *name);
+
+#endif /* AVUTIL_SUBFMT_H */