summaryrefslogtreecommitdiff
path: root/ffmpeg/libavcodec/dvdsubdec.c
diff options
context:
space:
mode:
authorTim Redfern <tim@eclectronics.org>2013-12-29 12:19:38 +0000
committerTim Redfern <tim@eclectronics.org>2013-12-29 12:19:38 +0000
commitf7813a5324be39d13ab536c245d15dfc602a7849 (patch)
treefad99148b88823d34a5df2f0a25881a002eb291b /ffmpeg/libavcodec/dvdsubdec.c
parentb7a5a477b8ff4d4e3028b9dfb9a9df0a41463f92 (diff)
basic type mechanism working
Diffstat (limited to 'ffmpeg/libavcodec/dvdsubdec.c')
-rw-r--r--ffmpeg/libavcodec/dvdsubdec.c124
1 files changed, 91 insertions, 33 deletions
diff --git a/ffmpeg/libavcodec/dvdsubdec.c b/ffmpeg/libavcodec/dvdsubdec.c
index cb268b8..637f3e6 100644
--- a/ffmpeg/libavcodec/dvdsubdec.c
+++ b/ffmpeg/libavcodec/dvdsubdec.c
@@ -21,13 +21,14 @@
#include "avcodec.h"
#include "get_bits.h"
#include "dsputil.h"
+#include "internal.h"
+
+#include "libavutil/attributes.h"
#include "libavutil/colorspace.h"
#include "libavutil/opt.h"
#include "libavutil/imgutils.h"
#include "libavutil/avstring.h"
-//#define DEBUG
-
typedef struct DVDSubContext
{
AVClass *class;
@@ -36,11 +37,16 @@ typedef struct DVDSubContext
int has_palette;
uint8_t colormap[4];
uint8_t alpha[256];
+ uint8_t *buf;
+ int buf_size;
+#ifdef DEBUG
+ int sub_id;
+#endif
} DVDSubContext;
static void yuv_a_to_rgba(const uint8_t *ycbcr, const uint8_t *alpha, uint32_t *rgba, int num_values)
{
- uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
+ const uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
uint8_t r, g, b;
int i, y, cb, cr;
int r_add, g_add, b_add;
@@ -185,6 +191,21 @@ static void guess_palette(DVDSubContext* ctx,
}
}
+static void reset_rects(AVSubtitle *sub_header)
+{
+ int i;
+
+ if (sub_header->rects != NULL) {
+ for (i = 0; i < sub_header->num_rects; i++) {
+ av_freep(&sub_header->rects[i]->pict.data[0]);
+ av_freep(&sub_header->rects[i]->pict.data[1]);
+ av_freep(&sub_header->rects[i]);
+ }
+ av_freep(&sub_header->rects);
+ sub_header->num_rects = 0;
+ }
+}
+
#define READ_OFFSET(a) (big_offsets ? AV_RB32(a) : AV_RB16(a))
static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
@@ -213,6 +234,9 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
cmd_pos = READ_OFFSET(buf + cmd_pos);
+ if (cmd_pos < 0 || cmd_pos > buf_size - 2 - offset_size)
+ return AVERROR(EAGAIN);
+
while (cmd_pos > 0 && cmd_pos < buf_size - 2 - offset_size) {
date = AV_RB16(buf + cmd_pos);
next_cmd_pos = READ_OFFSET(buf + cmd_pos + 2);
@@ -325,15 +349,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
if (h < 0)
h = 0;
if (w > 0 && h > 0) {
- if (sub_header->rects != NULL) {
- for (i = 0; i < sub_header->num_rects; i++) {
- av_freep(&sub_header->rects[i]->pict.data[0]);
- av_freep(&sub_header->rects[i]->pict.data[1]);
- av_freep(&sub_header->rects[i]);
- }
- av_freep(&sub_header->rects);
- sub_header->num_rects = 0;
- }
+ reset_rects(sub_header);
bitmap = av_malloc(w * h);
sub_header->rects = av_mallocz(sizeof(*sub_header->rects));
@@ -375,15 +391,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header,
if (sub_header->num_rects > 0)
return is_menu;
fail:
- if (sub_header->rects != NULL) {
- for (i = 0; i < sub_header->num_rects; i++) {
- av_freep(&sub_header->rects[i]->pict.data[0]);
- av_freep(&sub_header->rects[i]->pict.data[1]);
- av_freep(&sub_header->rects[i]);
- }
- av_freep(&sub_header->rects);
- sub_header->num_rects = 0;
- }
+ reset_rects(sub_header);
return -1;
}
@@ -454,9 +462,6 @@ static int find_smallest_bounding_rectangle(AVSubtitle *s)
}
#ifdef DEBUG
-#undef fprintf
-#undef perror
-#undef exit
static void ppm_save(const char *filename, uint8_t *bitmap, int w, int h,
uint32_t *rgba_palette)
{
@@ -466,7 +471,7 @@ static void ppm_save(const char *filename, uint8_t *bitmap, int w, int h,
f = fopen(filename, "w");
if (!f) {
perror(filename);
- exit(1);
+ return;
}
fprintf(f, "P6\n"
"%d %d\n"
@@ -484,6 +489,25 @@ static void ppm_save(const char *filename, uint8_t *bitmap, int w, int h,
}
#endif
+static int append_to_cached_buf(AVCodecContext *avctx,
+ const uint8_t *buf, int buf_size)
+{
+ DVDSubContext *ctx = avctx->priv_data;
+
+ if (ctx->buf_size > 0xffff - buf_size) {
+ av_log(avctx, AV_LOG_WARNING, "Attempt to reconstruct "
+ "too large SPU packets aborted.\n");
+ av_freep(&ctx->buf);
+ return AVERROR_INVALIDDATA;
+ }
+ ctx->buf = av_realloc(ctx->buf, ctx->buf_size + buf_size);
+ if (!ctx->buf)
+ return AVERROR(ENOMEM);
+ memcpy(ctx->buf + ctx->buf_size, buf, buf_size);
+ ctx->buf_size += buf_size;
+ return 0;
+}
+
static int dvdsub_decode(AVCodecContext *avctx,
void *data, int *data_size,
AVPacket *avpkt)
@@ -494,7 +518,21 @@ static int dvdsub_decode(AVCodecContext *avctx,
AVSubtitle *sub = data;
int is_menu;
+ if (ctx->buf) {
+ int ret = append_to_cached_buf(avctx, buf, buf_size);
+ if (ret < 0) {
+ *data_size = 0;
+ return ret;
+ }
+ buf = ctx->buf;
+ buf_size = ctx->buf_size;
+ }
+
is_menu = decode_dvd_subtitles(ctx, sub, buf, buf_size);
+ if (is_menu == AVERROR(EAGAIN)) {
+ *data_size = 0;
+ return append_to_cached_buf(avctx, buf, buf_size);
+ }
if (is_menu < 0) {
no_subtitle:
@@ -506,13 +544,20 @@ static int dvdsub_decode(AVCodecContext *avctx,
goto no_subtitle;
#if defined(DEBUG)
+ {
+ char ppm_name[32];
+
+ snprintf(ppm_name, sizeof(ppm_name), "/tmp/%05d.ppm", ctx->sub_id++);
av_dlog(NULL, "start=%d ms end =%d ms\n",
sub->start_display_time,
sub->end_display_time);
- ppm_save("/tmp/a.ppm", sub->rects[0]->pict.data[0],
+ ppm_save(ppm_name, sub->rects[0]->pict.data[0],
sub->rects[0]->w, sub->rects[0]->h, sub->rects[0]->pict.data[1]);
+ }
#endif
+ av_freep(&ctx->buf);
+ ctx->buf_size = 0;
*data_size = 1;
return buf_size;
}
@@ -552,9 +597,13 @@ static int dvdsub_parse_extradata(AVCodecContext *avctx)
parse_palette(ctx, data + 8);
} else if (strncmp("size:", data, 5) == 0) {
int w, h;
- if (sscanf(data + 5, "%dx%d", &w, &h) == 2 &&
- av_image_check_size(w, h, 0, avctx) >= 0)
- avcodec_set_dimensions(avctx, w, h);
+ if (sscanf(data + 5, "%dx%d", &w, &h) == 2) {
+ int ret = ff_set_dimensions(avctx, w, h);
+ if (ret < 0) {
+ av_free(dataorig);
+ return ret;
+ }
+ }
}
data += pos;
@@ -565,7 +614,7 @@ static int dvdsub_parse_extradata(AVCodecContext *avctx)
return 1;
}
-static int dvdsub_init(AVCodecContext *avctx)
+static av_cold int dvdsub_init(AVCodecContext *avctx)
{
DVDSubContext *ctx = avctx->priv_data;
int ret;
@@ -586,13 +635,21 @@ static int dvdsub_init(AVCodecContext *avctx)
return 1;
}
+static av_cold int dvdsub_close(AVCodecContext *avctx)
+{
+ DVDSubContext *ctx = avctx->priv_data;
+ av_freep(&ctx->buf);
+ ctx->buf_size = 0;
+ return 0;
+}
+
#define OFFSET(field) offsetof(DVDSubContext, field)
#define VD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
static const AVOption options[] = {
{ "palette", "set the global palette", OFFSET(palette_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, VD },
{ NULL }
};
-static const AVClass class = {
+static const AVClass dvdsub_class = {
.class_name = "dvdsubdec",
.item_name = av_default_item_name,
.option = options,
@@ -601,11 +658,12 @@ static const AVClass class = {
AVCodec ff_dvdsub_decoder = {
.name = "dvdsub",
+ .long_name = NULL_IF_CONFIG_SMALL("DVD subtitles"),
.type = AVMEDIA_TYPE_SUBTITLE,
.id = AV_CODEC_ID_DVD_SUBTITLE,
.priv_data_size = sizeof(DVDSubContext),
.init = dvdsub_init,
.decode = dvdsub_decode,
- .long_name = NULL_IF_CONFIG_SMALL("DVD subtitles"),
- .priv_class = &class,
+ .close = dvdsub_close,
+ .priv_class = &dvdsub_class,
};