[FFmpeg-devel] [PATCH v22 03/23] avcodec/subtitles: Introduce new frame-based subtitle decoding API
Soft Works
softworkz at hotmail.com
Thu Dec 9 14:12:32 EET 2021
- Add avcodec_decode_subtitle3 which takes subtitle frames,
serving as compatibility shim to legacy subtitle decoding
- Add additional methods for conversion between old and new API
Signed-off-by: softworkz <softworkz at hotmail.com>
---
libavcodec/avcodec.h | 8 +-
libavcodec/codec_desc.c | 11 +++
libavcodec/codec_desc.h | 8 ++
libavcodec/decode.c | 54 ++++++++++--
libavcodec/internal.h | 16 ++++
libavcodec/utils.c | 182 ++++++++++++++++++++++++++++++++++++++++
6 files changed, 270 insertions(+), 9 deletions(-)
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index b05c12e47e..3e734d3003 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -1675,7 +1675,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())
@@ -2417,7 +2417,10 @@ int avcodec_close(AVCodecContext *avctx);
* Free all allocated data in the given subtitle struct.
*
* @param sub AVSubtitle to free.
+ *
+ * @deprecated Use the regular frame based encode and decode APIs instead.
*/
+attribute_deprecated
void avsubtitle_free(AVSubtitle *sub);
/**
@@ -2510,7 +2513,10 @@ enum AVChromaLocation avcodec_chroma_pos_to_enum(int xpos, int ypos);
* must be freed with avsubtitle_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.
+ *
+ * @deprecated Use the new decode API (avcodec_send_packet, avcodec_receive_frame) instead.
*/
+attribute_deprecated
int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
int *got_sub_ptr,
AVPacket *avpkt);
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 0974ee03de..e48e4532ba 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -3548,3 +3548,14 @@ enum AVMediaType avcodec_get_type(enum AVCodecID codec_id)
const AVCodecDescriptor *desc = avcodec_descriptor_get(codec_id);
return desc ? desc->type : AVMEDIA_TYPE_UNKNOWN;
}
+
+enum AVSubtitleType avcodec_descriptor_get_subtitle_format(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;
+}
diff --git a/libavcodec/codec_desc.h b/libavcodec/codec_desc.h
index 126b52df47..ba68d24e0e 100644
--- a/libavcodec/codec_desc.h
+++ b/libavcodec/codec_desc.h
@@ -121,6 +121,14 @@ const AVCodecDescriptor *avcodec_descriptor_next(const AVCodecDescriptor *prev);
*/
const AVCodecDescriptor *avcodec_descriptor_get_by_name(const char *name);
+/**
+ * Return subtitle format from a codec descriptor
+ *
+ * @param codec_descriptor codec descriptor
+ * @return the subtitle type (e.g. bitmap, text)
+ */
+enum AVSubtitleType avcodec_descriptor_get_subtitle_format(const AVCodecDescriptor *codec_descriptor);
+
/**
* @}
*/
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 52bf5dcd33..ac267f0df6 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -576,6 +576,37 @@ static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame)
return ret;
}
+static int decode_subtitle2_priv(AVCodecContext *avctx, AVSubtitle *sub,
+ int *got_sub_ptr, AVPacket *avpkt);
+
+static int decode_subtitle_shim(AVCodecContext *avctx, AVFrame *frame, AVPacket *avpkt)
+{
+ int ret, got_sub_ptr = 0;
+ AVSubtitle subtitle = { 0 };
+
+ if (frame->buf[0])
+ return AVERROR(EAGAIN);
+
+ av_frame_unref(frame);
+
+ ret = decode_subtitle2_priv(avctx, &subtitle, &got_sub_ptr, avpkt);
+
+ if (ret >= 0 && got_sub_ptr) {
+ frame->type = AVMEDIA_TYPE_SUBTITLE;
+ frame->format = subtitle.format;
+ ret = av_frame_get_buffer2(frame, 0);
+
+ if (ret >= 0)
+ ret = ff_frame_put_subtitle(frame, &subtitle);
+
+ frame->pkt_dts = avpkt->dts;
+ }
+
+ avsubtitle_free(&subtitle);
+
+ return ret;
+}
+
int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt)
{
AVCodecInternal *avci = avctx->internal;
@@ -590,6 +621,9 @@ int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacke
if (avpkt && !avpkt->size && avpkt->data)
return AVERROR(EINVAL);
+ if (avctx->codec_type == AVMEDIA_TYPE_SUBTITLE)
+ return decode_subtitle_shim(avctx, avci->buffer_frame, avpkt);
+
av_packet_unref(avci->buffer_pkt);
if (avpkt && (avpkt->data || avpkt->side_data_elems)) {
ret = av_packet_ref(avci->buffer_pkt, avpkt);
@@ -651,7 +685,9 @@ int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *fr
if (avci->buffer_frame->buf[0]) {
av_frame_move_ref(frame, avci->buffer_frame);
- } else {
+ } else if (avctx->codec_type == AVMEDIA_TYPE_SUBTITLE)
+ return AVERROR(EAGAIN);
+ else {
ret = decode_receive_frame_internal(avctx, frame);
if (ret < 0)
return ret;
@@ -802,9 +838,8 @@ static int utf8_check(const uint8_t *str)
return 1;
}
-int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
- int *got_sub_ptr,
- AVPacket *avpkt)
+static int decode_subtitle2_priv(AVCodecContext *avctx, AVSubtitle *sub,
+ int *got_sub_ptr, AVPacket *avpkt)
{
int ret = 0;
@@ -844,10 +879,7 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
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 = avcodec_descriptor_get_subtitle_format(avctx->codec_descriptor);
for (unsigned i = 0; i < sub->num_rects; i++) {
if (avctx->sub_charenc_mode != FF_SUB_CHARENC_MODE_IGNORE &&
@@ -871,6 +903,12 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
return ret;
}
+int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
+ int *got_sub_ptr, AVPacket *avpkt)
+{
+ return decode_subtitle2_priv(avctx, sub, got_sub_ptr, avpkt);
+}
+
enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *avctx,
const enum AVPixelFormat *fmt)
{
diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index a62f8dbd4e..10443ed2d1 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -363,6 +363,22 @@ int ff_int_from_list_or_default(void *ctx, const char * val_name, int val,
void ff_dvdsub_parse_palette(uint32_t *palette, const char *p);
+/**
+ * Copies subtitle data from AVSubtitle to AVFrame.
+ *
+ * @deprecated This is a compatibility method for interoperability with
+ * the legacy subtitle API.
+ */
+int ff_frame_put_subtitle(AVFrame* frame, const AVSubtitle* sub);
+
+/**
+ * Copies subtitle data from AVFrame to AVSubtitle.
+ *
+ * @deprecated This is a compatibility method for interoperability with
+ * the legacy subtitle API.
+ */
+int ff_frame_get_subtitle(AVSubtitle* sub, AVFrame* frame);
+
#if defined(_WIN32) && CONFIG_SHARED && !defined(BUILDING_avcodec)
# define av_export_avcodec __declspec(dllimport)
#else
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index a91a54b0dc..613c580c19 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -824,6 +824,188 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes)
return FFMAX(0, duration);
}
+static int subtitle_area2rect(AVSubtitleRect *dst, const AVSubtitleArea *src)
+{
+ dst->x = src->x;
+ dst->y = src->y;
+ dst->w = src->w;
+ dst->h = src->h;
+ dst->nb_colors = src->nb_colors;
+ dst->type = src->type;
+ dst->flags = src->flags;
+
+ switch (dst->type) {
+ case AV_SUBTITLE_FMT_BITMAP:
+
+ if (src->h > 0 && src->w > 0 && src->buf[0]) {
+ uint32_t *pal;
+ AVBufferRef *buf = src->buf[0];
+ dst->data[0] = av_mallocz(buf->size);
+ memcpy(dst->data[0], buf->data, buf->size);
+ dst->linesize[0] = src->linesize[0];
+
+ dst->data[1] = av_mallocz(256 * 4);
+ pal = (uint32_t *)dst->data[1];
+
+ for (unsigned i = 0; i < 256; i++) {
+ pal[i] = src->pal[i];
+ }
+ }
+
+ break;
+ case AV_SUBTITLE_FMT_TEXT:
+
+ if (src->text)
+ dst->text = av_strdup(src->text);
+ else
+ dst->text = av_strdup("");
+
+ if (!dst->text)
+ return AVERROR(ENOMEM);
+
+ break;
+ case AV_SUBTITLE_FMT_ASS:
+
+ if (src->ass)
+ dst->ass = av_strdup(src->ass);
+ else
+ dst->ass = av_strdup("");
+
+ if (!dst->ass)
+ return AVERROR(ENOMEM);
+
+ break;
+ default:
+
+ av_log(NULL, AV_LOG_ERROR, "Subtitle rect has invalid format: %d", dst->type);
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+static int subtitle_rect2area(AVSubtitleArea *dst, const AVSubtitleRect *src)
+{
+ dst->x = src->x;
+ dst->y = src->y;
+ dst->w = src->w;
+ dst->h = src->h;
+ dst->nb_colors = src->nb_colors;
+ dst->type = src->type;
+ dst->flags = src->flags;
+
+ switch (dst->type) {
+ case AV_SUBTITLE_FMT_BITMAP:
+
+ if (src->h > 0 && src->w > 0 && src->data[0]) {
+ AVBufferRef *buf = av_buffer_allocz(src->h * src->linesize[0]);
+ memcpy(buf->data, src->data[0], buf->size);
+
+ dst->buf[0] = buf;
+ dst->linesize[0] = src->linesize[0];
+ }
+
+ if (src->data[1]) {
+ uint32_t *pal = (uint32_t *)src->data[1];
+
+ for (unsigned i = 0; i < 256; i++) {
+ dst->pal[i] = pal[i];
+ }
+ }
+
+ break;
+ case AV_SUBTITLE_FMT_TEXT:
+
+ if (src->text) {
+ dst->text = av_strdup(src->text);
+ if (!dst->text)
+ return AVERROR(ENOMEM);
+ }
+
+ break;
+ case AV_SUBTITLE_FMT_ASS:
+
+ if (src->ass) {
+ dst->ass = av_strdup(src->ass);
+ if (!dst->ass)
+ return AVERROR(ENOMEM);
+ }
+
+ break;
+ default:
+
+ av_log(NULL, AV_LOG_ERROR, "Subtitle area has invalid format: %d", dst->type);
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+/**
+ * Copies subtitle data from AVSubtitle (deprecated) to AVFrame
+ *
+ * @note This is a compatibility method for conversion to the legacy API
+ */
+int ff_frame_put_subtitle(AVFrame *frame, const AVSubtitle *sub)
+{
+ frame->format = sub->format;
+ frame->subtitle_start_time = sub->start_display_time;
+ frame->subtitle_end_time = sub->end_display_time;
+ frame->subtitle_pts = sub->pts;
+
+ if (sub->num_rects) {
+ frame->subtitle_areas = av_malloc_array(sub->num_rects, sizeof(AVSubtitleArea*));
+ if (!frame->subtitle_areas)
+ return AVERROR(ENOMEM);
+
+ for (unsigned i = 0; i < sub->num_rects; i++) {
+ int ret;
+ frame->subtitle_areas[i] = av_mallocz(sizeof(AVSubtitleArea));
+ if (!frame->subtitle_areas[i])
+ return AVERROR(ENOMEM);
+ ret = subtitle_rect2area(frame->subtitle_areas[i], sub->rects[i]);
+ if (ret < 0) {
+ frame->num_subtitle_areas = i;
+ return ret;
+ }
+ }
+ }
+
+ frame->num_subtitle_areas = sub->num_rects;
+ return 0;
+}
+
+/**
+ * Copies subtitle data from AVFrame to AVSubtitle (deprecated)
+ *
+ * @note This is a compatibility method for conversion to the legacy API
+ */
+int ff_frame_get_subtitle(AVSubtitle *sub, AVFrame *frame)
+{
+ sub->start_display_time = frame->subtitle_start_time;
+ sub->end_display_time = frame->subtitle_end_time;
+ sub->pts = frame->subtitle_pts;
+
+ if (frame->num_subtitle_areas) {
+ sub->rects = av_malloc_array(frame->num_subtitle_areas, sizeof(AVSubtitleRect*));
+ if (!sub->rects)
+ return AVERROR(ENOMEM);
+
+ for (unsigned i = 0; i < frame->num_subtitle_areas; i++) {
+ int ret;
+ sub->rects[i] = av_mallocz(sizeof(AVSubtitleRect));
+ ret = subtitle_area2rect(sub->rects[i], frame->subtitle_areas[i]);
+ if (ret < 0) {
+ sub->num_rects = i;
+ return ret;
+ }
+ }
+ }
+
+ sub->num_rects = frame->num_subtitle_areas;
+ return 0;
+}
+
int av_get_audio_frame_duration2(AVCodecParameters *par, int frame_bytes)
{
int duration = get_audio_frame_duration(par->codec_id, par->sample_rate,
--
2.30.2.windows.1
More information about the ffmpeg-devel
mailing list