aboutsummaryrefslogtreecommitdiffstats
path: root/libavcodec
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2005-07-17 00:28:12 +0000
committerMichael Niedermayer <michaelni@gmx.at>2005-07-17 00:28:12 +0000
commitc6ec28b18cd1eb7d39e6163137367f2d1c62aa7c (patch)
treea0055aeb706ad0230cf7bc7cc8b48d582057f9d8 /libavcodec
parent6e5c1877b2a93dd63610a1504e95bddc891424f3 (diff)
downloadffmpeg-c6ec28b18cd1eb7d39e6163137367f2d1c62aa7c.tar.gz
DVB subtitle decoder by (Ian Caulfield: imc25, cam ac uk)
Originally committed as revision 4448 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavcodec')
-rw-r--r--libavcodec/Makefile2
-rw-r--r--libavcodec/allcodecs.c2
-rw-r--r--libavcodec/avcodec.h15
-rw-r--r--libavcodec/dvbsub.c228
-rw-r--r--libavcodec/dvbsubdec.c1633
5 files changed, 1779 insertions, 101 deletions
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index d7c7227d1a..086c28b9eb 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -17,7 +17,7 @@ OBJS= bitstream.o utils.o mem.o allcodecs.o \
ratecontrol.o adpcm.o eval.o error_resilience.o \
fft.o mdct.o raw.o golomb.o cabac.o\
dpcm.o adx.o rational.o faandct.o parser.o g726.o \
- vp3dsp.o integer.o h264idct.o rangecoder.o pnm.o h263.o msmpeg4.o h263dec.o dvdsub.o dvbsub.o
+ vp3dsp.o integer.o h264idct.o rangecoder.o pnm.o h263.o msmpeg4.o h263dec.o dvdsub.o dvbsub.o dvbsubdec.o
ifeq ($(CONFIG_AASC_DECODER),yes)
OBJS+= aasc.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index eb00ac432b..ae79b693c1 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -555,6 +555,7 @@ PCM_CODEC(CODEC_ID_ADPCM_YAMAHA, adpcm_yamaha);
/* subtitles */
register_avcodec(&dvdsub_decoder);
register_avcodec(&dvbsub_encoder);
+ register_avcodec(&dvbsub_decoder);
/* parsers */
av_register_codec_parser(&mpegvideo_parser);
@@ -574,5 +575,6 @@ PCM_CODEC(CODEC_ID_ADPCM_YAMAHA, adpcm_yamaha);
av_register_codec_parser(&ac3_parser);
#endif
av_register_codec_parser(&dvdsub_parser);
+ av_register_codec_parser(&dvbsub_parser);
}
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 178e65f0f6..43029a58b2 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -1930,18 +1930,23 @@ typedef struct AVPaletteControl {
} AVPaletteControl;
-typedef struct AVSubtitle {
- uint16_t format; /* 0 = graphics */
+typedef struct AVSubtitleRect {
uint16_t x;
uint16_t y;
uint16_t w;
uint16_t h;
uint16_t nb_colors;
- uint32_t start_display_time; /* relative to packet pts, in ms */
- uint32_t end_display_time; /* relative to packet pts, in ms */
int linesize;
uint32_t *rgba_palette;
uint8_t *bitmap;
+} 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 */
+ uint32_t num_rects;
+ AVSubtitleRect *rects;
} AVSubtitle;
extern AVCodec ac3_encoder;
@@ -2135,6 +2140,7 @@ extern AVCodec dts_decoder;
/* subtitles */
extern AVCodec dvdsub_decoder;
extern AVCodec dvbsub_encoder;
+extern AVCodec dvbsub_decoder;
/* resample.c */
@@ -2390,6 +2396,7 @@ extern AVCodecParser pnm_parser;
extern AVCodecParser mpegaudio_parser;
extern AVCodecParser ac3_parser;
extern AVCodecParser dvdsub_parser;
+extern AVCodecParser dvbsub_parser;
/* memory */
void *av_malloc(unsigned int size);
diff --git a/libavcodec/dvbsub.c b/libavcodec/dvbsub.c
index 9b52848d98..8efe8b2f98 100644
--- a/libavcodec/dvbsub.c
+++ b/libavcodec/dvbsub.c
@@ -225,18 +225,9 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s,
q = outbuf;
page_id = 1;
- region_id = 0;
- clut_id = 0;
- object_id = 0;
- if (h->nb_colors <= 4) {
- /* 2 bpp, some decoders do not support it correctly */
- bpp_index = 0;
- } else if (h->nb_colors <= 16) {
- /* 4 bpp, standard encoding */
- bpp_index = 1;
- } else {
+
+ if (h->num_rects == 0 || h->rects == NULL)
return -1;
- }
*q++ = 0x00; /* subtitle_stream_id */
@@ -254,108 +245,153 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s,
page_state = 2; /* mode change */
/* page_version = 0 + page_state */
*q++ = s->object_version | (page_state << 2) | 3;
- *q++ = region_id;
- *q++ = 0xff; /* reserved */
- putbe16(&q, 0); /* left pos */
- putbe16(&q, 0); /* top pos */
+
+ for (region_id = 0; region_id < h->num_rects; region_id++) {
+ *q++ = region_id;
+ *q++ = 0xff; /* reserved */
+ putbe16(&q, h->rects[region_id].x); /* left pos */
+ putbe16(&q, h->rects[region_id].y); /* top pos */
+ }
putbe16(&pseg_len, q - pseg_len - 2);
if (!s->hide_state) {
- /* CLUT segment */
+ for (clut_id = 0; clut_id < h->num_rects; clut_id++) {
+
+ /* CLUT segment */
+
+ if (h->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) {
+ /* 4 bpp, standard encoding */
+ bpp_index = 1;
+ } else {
+ return -1;
+ }
+
+ *q++ = 0x0f; /* sync byte */
+ *q++ = 0x12; /* CLUT definition segment */
+ putbe16(&q, page_id);
+ pseg_len = q;
+ q += 2; /* segment length */
+ *q++ = clut_id;
+ *q++ = (0 << 4) | 0xf; /* version = 0 */
+
+ for(i = 0; i < h->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;
+ a = (h->rects[clut_id].rgba_palette[i] >> 24) & 0xff;
+ r = (h->rects[clut_id].rgba_palette[i] >> 16) & 0xff;
+ g = (h->rects[clut_id].rgba_palette[i] >> 8) & 0xff;
+ b = (h->rects[clut_id].rgba_palette[i] >> 0) & 0xff;
+
+ *q++ = RGB_TO_Y_CCIR(r, g, b);
+ *q++ = RGB_TO_V_CCIR(r, g, b, 0);
+ *q++ = RGB_TO_U_CCIR(r, g, b, 0);
+ *q++ = 255 - a;
+ }
+ }
+
+ putbe16(&pseg_len, q - pseg_len - 2);
+ }
+ }
+
+ for (region_id = 0; region_id < h->num_rects; region_id++) {
+
+ /* region composition segment */
- *q++ = 0x0f; /* sync byte */
- *q++ = 0x12; /* CLUT definition segment */
+ if (h->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) {
+ /* 4 bpp, standard encoding */
+ bpp_index = 1;
+ } else {
+ return -1;
+ }
+
+ *q++ = 0x0f; /* sync_byte */
+ *q++ = 0x11; /* segment_type */
putbe16(&q, page_id);
pseg_len = q;
q += 2; /* segment length */
- *q++ = clut_id;
- *q++ = (0 << 4) | 0xf; /* version = 0 */
-
- for(i = 0; i < h->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;
- a = (h->rgba_palette[i] >> 24) & 0xff;
- r = (h->rgba_palette[i] >> 16) & 0xff;
- g = (h->rgba_palette[i] >> 8) & 0xff;
- b = (h->rgba_palette[i] >> 0) & 0xff;
-
- *q++ = RGB_TO_Y_CCIR(r, g, b);
- *q++ = RGB_TO_V_CCIR(r, g, b, 0);
- *q++ = RGB_TO_U_CCIR(r, g, b, 0);
- *q++ = 255 - a;
- }
+ *q++ = region_id;
+ *q++ = (s->object_version << 4) | (0 << 3) | 0x07; /* version , no fill */
+ putbe16(&q, h->rects[region_id].w); /* region width */
+ putbe16(&q, h->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 */
+ *q++ = 0x03; /* 4 bit and 2 bit fill colors */
+
+ if (!s->hide_state) {
+ putbe16(&q, region_id); /* object_id == region_id */
+ *q++ = (0 << 6) | (0 << 4);
+ *q++ = 0;
+ *q++ = 0xf0;
+ *q++ = 0;
}
putbe16(&pseg_len, q - pseg_len - 2);
}
- /* region composition segment */
-
- *q++ = 0x0f; /* sync_byte */
- *q++ = 0x11; /* segment_type */
- putbe16(&q, page_id);
- pseg_len = q;
- q += 2; /* segment length */
- *q++ = region_id;
- *q++ = (s->object_version << 4) | (0 << 3) | 0x07; /* version , no fill */
- putbe16(&q, 720); /* region width */
- putbe16(&q, 576); /* region height */
- *q++ = ((1 + bpp_index) << 5) | ((1 + bpp_index) << 2) | 0x03;
- *q++ = clut_id;
- *q++ = 0; /* 8 bit fill colors */
- *q++ = 0x03; /* 4 bit and 2 bit fill colors */
-
- if (!s->hide_state) {
- putbe16(&q, object_id);
- *q++ = (0 << 6) | (0 << 4) | ((h->x >> 8) & 0xf);
- *q++ = h->x;
- *q++ = 0xf0 | ((h->y >> 8) & 0xf);
- *q++ = h->y;
- }
-
- putbe16(&pseg_len, q - pseg_len - 2);
if (!s->hide_state) {
- /* Object Data segment */
+ for (object_id = 0; object_id < h->num_rects; object_id++) {
+ /* Object Data segment */
+
+ if (h->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) {
+ /* 4 bpp, standard encoding */
+ bpp_index = 1;
+ } else {
+ return -1;
+ }
- *q++ = 0x0f; /* sync byte */
- *q++ = 0x13;
- putbe16(&q, page_id);
- pseg_len = q;
- q += 2; /* segment length */
-
- putbe16(&q, object_id);
- *q++ = (s->object_version << 4) | (0 << 2) | (0 << 1) | 1; /* version = 0,
- onject_coding_method,
- non_modifying_color_flag */
- {
- uint8_t *ptop_field_len, *pbottom_field_len, *top_ptr, *bottom_ptr;
- void (*dvb_encode_rle)(uint8_t **pq,
- const uint8_t *bitmap, int linesize,
- int w, int h);
- ptop_field_len = q;
- q += 2;
- pbottom_field_len = q;
- q += 2;
-
- if (bpp_index == 0)
- dvb_encode_rle = dvb_encode_rle2;
- else
- dvb_encode_rle = dvb_encode_rle4;
-
- top_ptr = q;
- dvb_encode_rle(&q, h->bitmap, h->w * 2, h->w, h->h >> 1);
- bottom_ptr = q;
- dvb_encode_rle(&q, h->bitmap + h->w, h->w * 2, h->w, h->h >> 1);
-
- putbe16(&ptop_field_len, bottom_ptr - top_ptr);
- putbe16(&pbottom_field_len, q - bottom_ptr);
- }
+ *q++ = 0x0f; /* sync byte */
+ *q++ = 0x13;
+ putbe16(&q, page_id);
+ pseg_len = q;
+ q += 2; /* segment length */
- putbe16(&pseg_len, q - pseg_len - 2);
+ putbe16(&q, object_id);
+ *q++ = (s->object_version << 4) | (0 << 2) | (0 << 1) | 1; /* version = 0,
+ onject_coding_method,
+ non_modifying_color_flag */
+ {
+ uint8_t *ptop_field_len, *pbottom_field_len, *top_ptr, *bottom_ptr;
+ void (*dvb_encode_rle)(uint8_t **pq,
+ const uint8_t *bitmap, int linesize,
+ int w, int h);
+ ptop_field_len = q;
+ q += 2;
+ pbottom_field_len = q;
+ q += 2;
+
+ if (bpp_index == 0)
+ dvb_encode_rle = dvb_encode_rle2;
+ else
+ dvb_encode_rle = dvb_encode_rle4;
+
+ top_ptr = q;
+ dvb_encode_rle(&q, h->rects[object_id].bitmap, h->rects[object_id].w * 2,
+ h->rects[object_id].w, h->rects[object_id].h >> 1);
+ bottom_ptr = q;
+ dvb_encode_rle(&q, h->rects[object_id].bitmap + h->rects[object_id].w,
+ h->rects[object_id].w * 2, h->rects[object_id].w,
+ h->rects[object_id].h >> 1);
+
+ putbe16(&ptop_field_len, bottom_ptr - top_ptr);
+ putbe16(&pbottom_field_len, q - bottom_ptr);
+ }
+
+ putbe16(&pseg_len, q - pseg_len - 2);
+ }
}
/* end of display set segment */
diff --git a/libavcodec/dvbsubdec.c b/libavcodec/dvbsubdec.c
new file mode 100644
index 0000000000..3309e61f37
--- /dev/null
+++ b/libavcodec/dvbsubdec.c
@@ -0,0 +1,1633 @@
+/*
+ * DVB subtitle decoding for ffmpeg
+ * Copyright (c) 2005 Ian Caulfield.
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "avcodec.h"
+#include "dsputil.h"
+#include "bitstream.h"
+
+//#define DEBUG
+//#define DEBUG_PACKET_CONTENTS
+//#define DEBUG_SAVE_IMAGES
+
+#define DVBSUB_PAGE_SEGMENT 0x10
+#define DVBSUB_REGION_SEGMENT 0x11
+#define DVBSUB_CLUT_SEGMENT 0x12
+#define DVBSUB_OBJECT_SEGMENT 0x13
+#define DVBSUB_DISPLAY_SEGMENT 0x80
+
+static unsigned char *cm;
+
+#ifdef DEBUG_SAVE_IMAGES
+#undef fprintf
+#if 0
+static void png_save(const char *filename, uint8_t *bitmap, int w, int h,
+ uint32_t *rgba_palette)
+{
+ int x, y, v;
+ FILE *f;
+ char fname[40], fname2[40];
+ char command[1024];
+
+ snprintf(fname, 40, "%s.ppm", filename);
+
+ f = fopen(fname, "w");
+ if (!f) {
+ perror(fname);
+ exit(1);
+ }
+ fprintf(f, "P6\n"
+ "%d %d\n"
+ "%d\n",
+ w, h, 255);
+ for(y = 0; y < h; y++) {
+ for(x = 0; x < w; x++) {
+ v = rgba_palette[bitmap[y * w + x]];
+ putc((v >> 16) & 0xff, f);
+ putc((v >> 8) & 0xff, f);
+ putc((v >> 0) & 0xff, f);
+ }
+ }
+ fclose(f);
+
+
+ snprintf(fname2, 40, "%s-a.pgm", filename);
+
+ f = fopen(fname2, "w");
+ if (!f) {
+ perror(fname2);
+ exit(1);
+ }
+ fprintf(f, "P5\n"
+ "%d %d\n"
+ "%d\n",
+ w, h, 255);
+ for(y = 0; y < h; y++) {
+ for(x = 0; x < w; x++) {
+ v = rgba_palette[bitmap[y * w + x]];
+ putc((v >> 24) & 0xff, f);
+ }
+ }
+ fclose(f);
+
+ snprintf(command, 1024, "pnmtopng -alpha %s %s > %s.png 2> /dev/null", fname2, fname, filename);
+ system(command);
+
+ snprintf(command, 1024, "rm %s %s", fname, fname2);
+ system(command);
+}
+#endif
+
+static void png_save2(const char *filename, uint32_t *bitmap, int w, int h)
+{
+ int x, y, v;
+ FILE *f;
+ char fname[40], fname2[40];
+ char command[1024];
+
+ snprintf(fname, 40, "%s.ppm", filename);
+
+ f = fopen(fname, "w");
+ if (!f) {
+ perror(fname);
+ exit(1);
+ }
+ fprintf(f, "P6\n"
+ "%d %d\n"
+ "%d\n",
+ w, h, 255);
+ for(y = 0; y < h; y++) {
+ for(x = 0; x < w; x++) {
+ v = bitmap[y * w + x];
+ putc((v >> 16) & 0xff, f);
+ putc((v >> 8) & 0xff, f);
+ putc((v >> 0) & 0xff, f);
+ }
+ }
+ fclose(f);
+
+
+ snprintf(fname2, 40, "%s-a.pgm", filename);
+
+ f = fopen(fname2, "w");
+ if (!f) {
+ perror(fname2);
+ exit(1);
+ }
+ fprintf(f, "P5\n"
+ "%d %d\n"
+ "%d\n",
+ w, h, 255);
+ for(y = 0; y < h; y++) {
+ for(x = 0; x < w; x++) {
+ v = bitmap[y * w + x];
+ putc((v >> 24) & 0xff, f);
+ }
+ }
+ fclose(f);
+
+ snprintf(command, 1024, "pnmtopng -alpha %s %s > %s.png 2> /dev/null", fname2, fname, filename);
+ system(command);
+
+ snprintf(command, 1024, "rm %s %s", fname, fname2);
+ system(command);
+}
+#endif
+
+#define RGBA(r,g,b,a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+
+typedef struct DVBSubCLUT {
+ int id;
+
+ uint32_t clut4[4];
+ uint32_t clut16[16];
+ uint32_t clut256[256];
+
+ struct DVBSubCLUT *next;
+} DVBSubCLUT;
+
+static DVBSubCLUT default_clut;
+
+typedef struct DVBSubObjectDisplay {
+ int object_id;
+ int region_id;
+
+ int x_pos;
+ int y_pos;
+
+ int fgcolour;
+ int bgcolour;
+
+ struct DVBSubObjectDisplay *region_list_next;
+ struct DVBSubObjectDisplay *object_list_next;
+} DVBSubObjectDisplay;
+
+typedef struct DVBSubObject {
+ int id;
+
+ int type;
+
+ DVBSubObjectDisplay *display_list;
+
+ struct DVBSubObject *next;
+} DVBSubObject;
+
+typedef struct DVBSubRegionDisplay {
+ int region_id;
+
+ int x_pos;
+ int y_pos;
+
+ struct DVBSubRegionDisplay *next;
+} DVBSubRegionDisplay;
+
+typedef struct DVBSubRegion {
+ int id;
+
+ int width;
+ int height;
+ int depth;
+
+ int clut;
+ int bgcolour;
+
+ uint8_t *pbuf;
+ int buf_size;
+
+ DVBSubObjectDisplay *display_list;
+
+ struct DVBSubRegion *next;
+} DVBSubRegion;
+
+typedef struct DVBSubContext {
+ int composition_id;
+ int ancillary_id;
+
+ int time_out;
+ DVBSubRegion *region_list;
+ DVBSubCLUT *clut_list;
+ DVBSubObject *object_list;
+
+ int display_list_size;
+ DVBSubRegionDisplay *display_list;
+} DVBSubContext;
+
+
+static DVBSubObject* get_object(DVBSubContext *ctx, int object_id)
+{
+ DVBSubObject *ptr = ctx->object_list;
+
+ while (ptr != NULL && ptr->id != object_id) {
+ ptr = ptr->next;
+ }
+
+ return ptr;
+}
+
+static DVBSubCLUT* get_clut(DVBSubContext *ctx, int clut_id)
+{
+ DVBSubCLUT *ptr = ctx->clut_list;
+
+ while (ptr != NULL && ptr->id != clut_id) {
+ ptr = ptr->next;
+ }
+
+ return ptr;
+}
+
+static DVBSubRegion* get_region(DVBSubContext *ctx, int region_id)
+{
+ DVBSubRegion *ptr = ctx->region_list;
+
+ while (ptr != NULL && ptr->id != region_id) {
+ ptr = ptr->next;
+ }
+
+ return ptr;
+}
+
+static void delete_region_display_list(DVBSubContext *ctx, DVBSubRegion *region)
+{
+ DVBSubObject *object, *obj2, **obj2_ptr;
+ DVBSubObjectDisplay *display, *obj_disp, **obj_disp_ptr;
+
+ while (region->display_list != NULL) {
+ display = region->display_list;
+
+ object = get_object(ctx, display->object_id);
+
+ if (object != NULL) {
+ obj_disp = object->display_list;
+ obj_disp_ptr = &object->display_list;
+
+ while (obj_disp != NULL && obj_disp != display) {
+ obj_disp_ptr = &obj_disp->object_list_next;
+ obj_disp = obj_disp->object_list_next;
+ }
+
+ if (obj_disp) {
+ *obj_disp_ptr = obj_disp->object_list_next;
+
+ if (object->display_list == NULL) {
+ obj2 = ctx->object_list;
+ obj2_ptr = &ctx->object_list;
+
+ while (obj2 != NULL && obj2 != object) {
+ obj2_ptr = &obj2->next;
+ obj2 = obj2->next;
+ }
+
+ *obj2_ptr = obj2->next;
+
+ av_free(obj2);
+ }
+ }
+ }
+
+ region->display_list = display->region_list_next;
+
+ av_free(display);
+ }
+
+}
+
+static void delete_state(DVBSubContext *ctx)
+{
+ DVBSubRegion *region;
+ DVBSubCLUT *clut;
+
+ while (ctx->region_list != NULL)
+ {
+ region = ctx->region_list;
+
+ ctx->region_list = region->next;
+
+ delete_region_display_list(ctx, region);
+ if (region->pbuf != NULL)
+ av_free(region->pbuf);
+
+ av_free(region);
+ }
+
+ while (ctx->clut_list != NULL)
+ {
+ clut = ctx->clut_list;
+
+ ctx->clut_list = clut->next;
+
+ av_free(clut);
+ }
+
+ /* Should already be null */
+ if (ctx->object_list != NULL)
+ av_log(0, AV_LOG_ERROR, "Memory deallocation error!\n");
+}
+
+static int dvbsub_init_decoder(AVCodecContext *avctx)
+{
+ int i, r, g, b, a = 0;
+ DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data;
+
+ cm = cropTbl + MAX_NEG_CROP;
+
+ memset(avctx->priv_data, 0, sizeof(DVBSubContext));
+
+ ctx->composition_id = avctx->sub_id & 0xffff;
+ ctx->ancillary_id = avctx->sub_id >> 16;
+
+ default_clut.id = -1;
+ default_clut.next = NULL;
+
+ default_clut.clut4[0] = RGBA( 0, 0, 0, 0);
+ default_clut.clut4[1] = RGBA(255, 255, 255, 255);
+ default_clut.clut4[2] = RGBA( 0, 0, 0, 255);
+ default_clut.clut4[3] = RGBA(127, 127, 127, 255);
+
+ default_clut.clut16[0] = RGBA( 0, 0, 0, 0);
+ for (i = 1; i < 16; i++) {
+ if (i < 8) {
+ r = (i & 1) ? 255 : 0;
+ g = (i & 2) ? 255 : 0;
+ b = (i & 4) ? 255 : 0;
+ } else {
+ r = (i & 1) ? 127 : 0;
+ g = (i & 2) ? 127 : 0;
+ b = (i & 4) ? 127 : 0;
+ }
+ default_clut.clut16[i] = RGBA(r, g, b, 255);
+ }
+
+ default_clut.clut256[0] = RGBA( 0, 0, 0, 0);
+ for (i = 1; i < 256; i++) {
+ if (i < 8) {
+ r = (i & 1) ? 255 : 0;
+ g = (i & 2) ? 255 : 0;
+ b = (i & 4) ? 255 : 0;
+ a = 63;
+ } else {
+ switch (i & 0x88) {
+ case 0x00:
+ r = ((i & 1) ? 85 : 0) + ((i & 0x10) ? 170 : 0);
+ g = ((i & 2) ? 85 : 0) + ((i & 0x20) ? 170 : 0);
+ b = ((i & 4) ? 85 : 0) + ((i & 0x40) ? 170 : 0);
+ a = 255;
+ break;
+ case 0x08:
+ r = ((i & 1) ? 85 : 0) + ((i & 0x10) ? 170 : 0);
+ g = ((i & 2) ? 85 : 0) + ((i & 0x20) ? 170 : 0);
+ b = ((i & 4) ? 85 : 0) + ((i & 0x40) ? 170 : 0);
+ a = 127;
+ break;
+ case 0x80:
+ r = 127 + ((i & 1) ? 43 : 0) + ((i & 0x10) ? 85 : 0);
+ g = 127 + ((i & 2) ? 43 : 0) + ((i & 0x20) ? 85 : 0);
+ b = 127 + ((i & 4) ? 43 : 0) + ((i & 0x40) ? 85 : 0);
+ a = 255;
+ break;
+ case 0x88:
+ r = ((i & 1) ? 43 : 0) + ((i & 0x10) ? 85 : 0);
+ g = ((i & 2) ? 43 : 0) + ((i & 0x20) ? 85 : 0);
+ b = ((i & 4) ? 43 : 0) + ((i & 0x40) ? 85 : 0);
+ a = 255;
+ break;
+ }
+ }
+ default_clut.clut256[i] = RGBA(r, g, b, a);
+ }
+
+ return 0;
+}
+
+static int dvbsub_close_decoder(AVCodecContext *avctx)
+{
+ DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data;
+ DVBSubRegionDisplay *display;
+
+ delete_state(ctx);
+
+ while (ctx->display_list != NULL)
+ {
+ display = ctx->display_list;
+ ctx->display_list = display->next;
+
+ av_free(display);
+ }
+
+ return 0;
+}
+
+static int dvbsub_read_2bit_string(uint8_t *destbuf, int dbuf_len,
+ uint8_t **srcbuf, int buf_size,
+ int non_mod, uint8_t *map_table)
+{
+ GetBitContext gb;
+
+ int bits;
+ int run_length;
+ int pixels_read = 0;
+
+ init_get_bits(&gb, *srcbuf, buf_size << 8);
+
+ while (get_bits_count(&gb) < (buf_size << 8) && pixels_read < dbuf_len) {
+ bits = get_bits(&gb, 2);
+
+ if (bits != 0) {
+ if (non_mod != 1 || bits != 1) {
+ if (map_table != NULL)
+ *destbuf++ = map_table[bits];
+ else
+ *destbuf++ = bits;
+ }
+ pixels_read++;
+ } else {
+ bits = get_bits(&gb, 1);
+ if (bits == 1) {
+ run_length = get_bits(&gb, 3) + 3;
+ bits = get_bits(&gb, 2);
+
+ if (non_mod == 1 && bits == 1)
+ pixels_read += run_length;
+ else {
+ if (map_table != NULL)
+ bits = map_table[bits];
+ while (run_length-- > 0 && pixels_read < dbuf_len) {
+ *destbuf++ = bits;
+ pixels_read++;
+ }
+ }
+ } else {
+ bits = get_bits(&gb, 1);
+ if (bits == 0) {
+ bits = get_bits(&gb, 2);
+ if (bits == 2) {
+ run_length = get_bits(&gb, 4) + 12;
+ bits = get_bits(&gb, 2);
+
+ if (non_mod == 1 && bits == 1)
+ pixels_read += run_length;
+ else {
+ if (map_table != NULL)
+ bits = map_table[bits];
+ while (run_length-- > 0 && pixels_read < dbuf_len) {
+ *destbuf++ = bits;
+ pixels_read++;
+ }
+ }
+ } else if (bits == 3) {
+ run_length = get_bits(&gb, 8) + 29;
+ bits = get_bits(&gb, 2);
+
+ if (non_mod == 1 && bits == 1)
+ pixels_read += run_length;
+ else {
+ if (map_table != NULL)
+ bits = map_table[bits];
+ while (run_length-- > 0 && pixels_read < dbuf_len) {
+ *destbuf++ = bits;
+ pixels_read++;
+ }
+ }
+ } else if (bits == 1) {
+ pixels_read += 2;
+ if (map_table != NULL)
+ bits = map_table[0];
+ else
+ bits = 0;
+ if (pixels_read <= dbuf_len) {
+ *destbuf++ = bits;
+ *destbuf++ = bits;
+ }
+ } else {
+ (*srcbuf) += (get_bits_count(&gb) + 7) >> 3;
+ return pixels_read;
+ }
+ } else {
+ if (map_table != NULL)
+ bits = map_table[0];
+ else
+ bits = 0;
+ *destbuf++ = bits;
+ pixels_read++;
+ }
+ }
+ }
+ }
+
+ if (get_bits(&gb, 6) != 0)
+ av_log(0, AV_LOG_ERROR, "DVBSub error: line overflow\n");
+
+ (*srcbuf) += (get_bits_count(&gb) + 7) >> 3;
+
+ return pixels_read;
+}
+
+static int dvbsub_read_4bit_string(uint8_t *destbuf, int dbuf_len,
+ uint8_t **srcbuf, int buf_size,
+ int non_mod, uint8_t *map_table)
+{
+ GetBitContext gb;
+
+ int bits;
+ int run_length;
+ int pixels_read = 0;
+
+ init_get_bits(&gb, *srcbuf, buf_size << 8);
+
+ while (get_bits_count(&gb) < (buf_size << 8) && pixels_read < dbuf_len) {
+ bits = get_bits(&gb, 4);
+
+ if (bits != 0) {
+ if (non_mod != 1 || bits != 1) {
+ if (map_table != NULL)
+ *destbuf++ = map_table[bits];
+ else
+ *destbuf++ = bits;
+ }
+ pixels_read++;
+ } else {
+ bits = get_bits(&gb, 1);
+ if (bits == 0) {
+ run_length = get_bits(&gb, 3);
+
+ if (run_length == 0) {
+ (*srcbuf) += (get_bits_count(&gb) + 7) >> 3;
+ return pixels_read;
+ }
+
+ run_length += 2;
+
+ if (map_table != NULL)
+ bits = map_table[0];
+ else
+ bits = 0;
+
+ while (run_length-- > 0 && pixels_read < dbuf_len) {
+ *destbuf++ = bits;
+ pixels_read++;
+ }
+ } else {
+ bits = get_bits(&gb, 1);
+ if (bits == 0) {
+ run_length = get_bits(&gb, 2) + 4;
+ bits = get_bits(&gb, 4);
+
+ if (non_mod == 1 && bits == 1)
+ pixels_read += run_length;
+ else {
+ if (map_table != NULL)
+ bits = map_table[bits];
+ while (run_length-- > 0 && pixels_read < dbuf_len) {
+ *destbuf++ = bits;
+ pixels_read++;
+ }
+ }
+ } else {
+ bits = get_bits(&gb, 2);
+ if (bits == 2) {
+ run_length = get_bits(&gb, 4) + 9;
+ bits = get_bits(&gb, 4);
+
+ if (non_mod == 1 && bits == 1)
+ pixels_read += run_length;
+ else {
+ if (map_table != NULL)
+ bits = map_table[bits];
+ while (run_length-- > 0 && pixels_read < dbuf_len) {
+ *destbuf++ = bits;
+ pixels_read++;
+ }
+ }
+ } else if (bits == 3) {
+ run_length = get_bits(&gb, 8) + 25;
+ bits = get_bits(&gb, 4);
+
+ if (non_mod == 1 && bits == 1)
+ pixels_read += run_length;
+ else {
+ if (map_table != NULL)
+ bits = map_table[bits];
+ while (run_length-- > 0 && pixels_read < dbuf_len) {
+ *destbuf++ = bits;
+ pixels_read++;
+ }
+ }
+ } else if (bits == 1) {
+ pixels_read += 2;
+ if (map_table != NULL)
+ bits = map_table[0];
+ else
+ bits = 0;
+ if (pixels_read <= dbuf_len) {
+ *destbuf++ = bits;
+ *destbuf++ = bits;
+ }
+ } else {
+ if (map_table != NULL)
+ bits = map_table[0];
+ else
+ bits = 0;
+ *destbuf++ = bits;
+ pixels_read ++;
+ }
+ }
+ }
+ }
+ }
+
+ if (get_bits(&gb, 8) != 0)
+ av_log(0, AV_LOG_ERROR, "DVBSub error: line overflow\n");
+
+ (*srcbuf) += (get_bits_count(&gb) + 7) >> 3;
+
+ return pixels_read;
+}
+
+static int dvbsub_read_8bit_string(uint8_t *destbuf, int dbuf_len,
+ uint8_t **srcbuf, int buf_size,
+ int non_mod, uint8_t *map_table)
+{
+ uint8_t *sbuf_end = (*srcbuf) + buf_size;
+ int bits;
+ int run_length;
+ int pixels_read = 0;
+
+ while (*srcbuf < sbuf_end && pixels_read < dbuf_len) {
+ bits = *(*srcbuf)++;
+
+ if (bits != 0) {
+ if (non_mod != 1 || bits != 1) {
+ if (map_table != NULL)
+ *destbuf++ = map_table[bits];
+ else
+ *destbuf++ = bits;
+ }
+ pixels_read++;
+ } else {
+ bits = *(*srcbuf)++;
+ run_length = bits & 0x7f;
+ if ((bits & 0x80) == 0) {
+ if (run_length == 0) {
+ return pixels_read;
+ }
+
+ if (map_table != NULL)
+ bits = map_table[0];
+ else
+ bits = 0;
+ while (run_length-- > 0 && pixels_read < dbuf_len) {
+ *destbuf++ = bits;
+ pixels_read++;
+ }
+ } else {
+ bits = *(*srcbuf)++;
+
+ if (non_mod == 1 && bits == 1)
+ pixels_read += run_length;
+ if (map_table != NULL)
+ bits = map_table[bits];
+ else while (run_length-- > 0 && pixels_read < dbuf_len) {
+ *destbuf++ = bits;
+ pixels_read++;
+ }
+ }
+ }
+ }
+
+ if (*(*srcbuf)++ != 0)
+ av_log(0, AV_LOG_ERROR, "DVBSub error: line overflow\n");
+
+ return pixels_read;
+}
+
+
+
+static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDisplay *display,
+ uint8_t *buf, int buf_size, int top_bottom, int non_mod)
+{
+ DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data;
+
+ DVBSubRegion *region = get_region(ctx, display->region_id);
+ uint8_t *buf_end = buf + buf_size;
+ uint8_t *pbuf;
+ int x_pos, y_pos;
+ int i;
+
+ uint8_t map2to4[] = { 0x0, 0x7, 0x8, 0xf};
+ uint8_t map2to8[] = {0x00, 0x77, 0x88, 0xff};
+ uint8_t map4to8[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
+ uint8_t *map_table;
+
+#ifdef DEBUG
+ av_log(avctx, AV_LOG_INFO, "DVB pixel block size %d, %s field:\n", buf_size,
+ top_bottom ? "bottom" : "top");
+#endif
+
+#ifdef DEBUG_PACKET_CONTENTS
+ for (i = 0; i < buf_size; i++)
+ {
+ if (i % 16 == 0)
+ av_log(avctx, AV_LOG_INFO, "0x%08p: ", buf+i);
+
+ av_log(avctx, AV_LOG_INFO, "%02x ", buf[i]);
+ if (i % 16 == 15)
+ av_log(avctx, AV_LOG_INFO, "\n");
+ }
+
+ if (i % 16 != 0)
+ av_log(avctx, AV_LOG_INFO, "\n");
+
+#endif
+
+ if (region == 0)
+ return;
+
+ pbuf = region->pbuf;
+
+ x_pos = display->x_pos;
+ y_pos = display->y_pos;
+
+ if ((y_pos & 1) != top_bottom)
+ y_pos++;
+
+ while (buf < buf_end) {
+ if (x_pos > region->width || y_pos > region->height) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid object location!\n");
+ return;
+ }
+
+ switch (*buf++) {
+ case 0x10:
+ if (region->depth == 8)
+ map_table = map2to8;
+ else if (region->depth == 4)
+ map_table = map2to4;
+ else
+ map_table = NULL;
+
+ x_pos += dvbsub_read_2bit_string(pbuf + (y_pos * region->width) + x_pos,
+ region->width - x_pos, &buf, buf_size,
+ non_mod, map_table);
+ break;
+ case 0x11:
+ if (region->depth < 4) {
+ av_log(avctx, AV_LOG_ERROR, "4-bit pixel string in %d-bit region!\n", region->depth);
+ return;
+ }
+
+ if (region->depth == 8)
+ map_table = map4to8;
+ else
+ map_table = NULL;
+
+ x_pos += dvbsub_read_4bit_string(pbuf + (y_pos * region->width) + x_pos,
+ region->width - x_pos, &buf, buf_size,
+ non_mod, map_table);
+ break;
+ case 0x12:
+ if (region->depth < 8) {
+ av_log(avctx, AV_LOG_ERROR, "8-bit pixel string in %d-bit region!\n", region->depth);
+ return;
+ }
+
+ x_pos += dvbsub_read_8bit_string(pbuf + (y_pos * region->width) + x_pos,
+ region->width - x_pos, &buf, buf_size,
+ non_mod, NULL);
+ break;
+
+ case 0x20:
+ map2to4[0] = (*buf) >> 4;
+ map2to4[1] = (*buf++) & 0xf;
+ map2to4[2] = (*buf) >> 4;
+ map2to4[3] = (*buf++) & 0xf;
+ break;
+ case 0x21:
+ for (i = 0; i < 4; i++)
+ map2to8[i] = *buf++;
+ break;
+ case 0x22:
+ for (i = 0; i < 16; i++)
+ map4to8[i] = *buf++;
+ break;
+
+ case 0xf0:
+ x_pos = display->x_pos;
+ y_pos += 2;
+ break;
+ default:
+ av_log(avctx, AV_LOG_INFO, "Unknown/unsupported pixel block 0x%x\n", *(buf-1));
+ }
+ }
+
+}
+
+static void dvbsub_parse_object_segment(AVCodecContext *avctx,
+ uint8_t *buf, int buf_size)
+{
+ DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data;
+
+ uint8_t *buf_end = buf + buf_size;
+ uint8_t *block;
+ int object_id;
+ DVBSubObject *object;
+ DVBSubObjectDisplay *display;
+ int top_field_len, bottom_field_len;
+
+ int coding_method, non_modifying_colour;
+
+ object_id = BE_16(buf);
+ buf += 2;
+
+ object = get_object(ctx, object_id);
+
+ if (!object)
+ return;
+
+ coding_method = ((*buf) >> 2) & 3;
+ non_modifying_colour = ((*buf++) >> 1) & 1;
+
+ if (coding_method == 0) {
+ top_field_len = BE_16(buf);
+ buf += 2;
+ bottom_field_len = BE_16(buf);
+ buf += 2;
+
+ if (buf + top_field_len + bottom_field_len > buf_end) {
+ av_log(avctx, AV_LOG_ERROR, "Field data size too large\n");
+ return;
+ }
+
+ for (display = object->display_list; display != 0; display = display->object_list_next) {
+ block = buf;
+
+ dvbsub_parse_pixel_data_block(avctx, display, block, top_field_len, 0,
+ non_modifying_colour);
+
+ if (bottom_field_len > 0)
+ block = buf + top_field_len;
+ else
+ bottom_field_len = top_field_len;
+
+ dvbsub_parse_pixel_data_block(avctx, display, block, bottom_field_len, 1,
+ non_modifying_colour);
+ }
+
+/* } else if (coding_method == 1) {*/
+
+ } else {
+ av_log(avctx, AV_LOG_ERROR, "Unknown object coding %d\n", coding_method);
+ }
+
+}
+
+#define SCALEBITS 10
+#define ONE_HALF (1 << (SCALEBITS - 1))
+#define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5))
+
+#define YUV_TO_RGB1_CCIR(cb1, cr1)\
+{\
+ cb = (cb1) - 128;\
+ cr = (cr1) - 128;\
+ r_add = FIX(1.40200*255.0/224.0) * cr + ONE_HALF;\
+ g_add = - FIX(0.34414*255.0/224.0) * cb - FIX(0.71414*255.0/224.0) * cr + \
+ ONE_HALF;\
+ b_add = FIX(1.77200*255.0/224.0) * cb + ONE_HALF;\
+}
+
+#define YUV_TO_RGB2_CCIR(r, g, b, y1)\
+{\
+ y = ((y1) - 16) * FIX(255.0/219.0);\
+ r = cm[(y + r_add) >> SCALEBITS];\
+ g = cm[(y + g_add) >> SCALEBITS];\
+ b = cm[(y + b_add) >> SCALEBITS];\
+}
+
+
+static void dvbsub_parse_clut_segment(AVCodecContext *avctx,
+ uint8_t *buf, int buf_size)
+{
+ DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data;
+
+ uint8_t *buf_end = buf + buf_size;
+ int clut_id;
+ DVBSubCLUT *clut;
+ int entry_id, depth , full_range;
+ int y, cr, cb, alpha;
+ int r, g, b, r_add, g_add, b_add;
+
+#ifdef DEBUG_PACKET_CONTENTS
+ int i;
+
+ av_log(avctx, AV_LOG_INFO, "DVB clut packet:\n");
+
+ for (i=0; i < buf_size; i++)
+ {
+ av_log(avctx, AV_LOG_INFO, "%02x ", buf[i]);
+ if (i % 16 == 15)
+ av_log(avctx, AV_LOG_INFO, "\n");
+ }
+
+ if (i % 16 != 0)
+ av_log(avctx, AV_LOG_INFO, "\n");
+
+#endif
+
+ clut_id = *buf++;
+ buf += 1;
+
+ clut = get_clut(ctx, clut_id);
+
+ if (clut == NULL) {
+ clut = av_malloc(sizeof(DVBSubCLUT));
+
+ memcpy(clut, &default_clut, sizeof(DVBSubCLUT));
+
+ clut->id = clut_id;
+
+ clut->next = ctx->clut_list;
+ ctx->clut_list = clut;
+ }
+
+ while (buf + 4 < buf_end)
+ {
+ entry_id = *buf++;
+
+ depth = (*buf) & 0xe0;
+
+ if (depth == 0) {
+ av_log(avctx, AV_LOG_ERROR, "Invalid clut depth 0x%x!\n", *buf);
+ return;
+ }
+
+ full_range = (*buf++) & 1;
+
+ if (full_range) {
+ y = *buf++;
+ cr = *buf++;
+ cb = *buf++;
+ alpha = *buf++;
+ } else {
+ y = buf[0] & 0xfc;
+ cr = (((buf[0] & 3) << 2) | ((buf[1] >> 6) & 3)) << 4;
+ cb = (buf[1] << 2) & 0xf0;
+ alpha = (buf[1] << 6) & 0xc0;
+
+ buf += 2;
+ }
+
+ if (y == 0)
+ alpha = 0xff;
+
+ YUV_TO_RGB1_CCIR(cb, cr);
+ YUV_TO_RGB2_CCIR(r, g, b, y);
+
+#ifdef DEBUG
+ av_log(avctx, AV_LOG_INFO, "clut %d := (%d,%d,%d,%d)\n", entry_id, r, g, b, alpha);
+#endif
+
+ if (depth & 0x80)
+ clut->clut4[entry_id] = RGBA(r,g,b,255 - alpha);
+ if (depth & 0x40)
+ clut->clut16[entry_id] = RGBA(r,g,b,255 - alpha);
+ if (depth & 0x20)
+ clut->clut256[entry_id] = RGBA(r,g,b,255 - alpha);
+ }
+}
+
+
+static void dvbsub_parse_region_segment(AVCodecContext *avctx,
+ uint8_t *buf, int buf_size)
+{
+ DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data;
+
+ uint8_t *buf_end = buf + buf_size;
+ int region_id, object_id;
+ DVBSubRegion *region;
+ DVBSubObject *object;
+ DVBSubObjectDisplay *display;
+ int fill;
+
+ if (buf_size < 10)
+ return;
+
+ region_id = *buf++;
+
+ region = get_region(ctx, region_id);
+
+ if (region == NULL)
+ {
+ region = av_mallocz(sizeof(DVBSubRegion));
+
+ region->id = region_id;
+
+ region->next = ctx->region_list;
+ ctx->region_list = region;
+ }
+
+ fill = ((*buf++) >> 3) & 1;
+
+ region->width = BE_16(buf);
+ buf += 2;
+ region->height = BE_16(buf);
+ buf += 2;
+
+ if (region->width * region->height != region->buf_size) {
+ if (region->pbuf != 0)
+ av_free(region->pbuf);
+
+ region->buf_size = region->width * region->height;
+
+ region->pbuf = av_malloc(region->buf_size);
+
+ fill = 1;
+ }
+
+ region->depth = 1 << (((*buf++) >> 2) & 7);
+ region->clut = *buf++;
+
+ if (region->depth == 8)
+ region->bgcolour = *buf++;
+ else {
+ buf += 1;
+
+ if (region->depth == 4)
+ region->bgcolour = (((*buf++) >> 4) & 15);
+ else
+ region->bgcolour = (((*buf++) >> 2) & 3);
+ }
+
+#ifdef DEBUG
+ av_log(avctx, AV_LOG_INFO, "Region %d, (%dx%d)\n", region_id, region->width, region->height);
+#endif
+
+ if (fill) {
+ memset(region->pbuf, region->bgcolour, region->buf_size);
+#ifdef DEBUG
+ av_log(avctx, AV_LOG_INFO, "Fill region (%d)\n", region->bgcolour);
+#endif
+ }
+
+ delete_region_display_list(ctx, region);
+
+ while (buf + 5 < buf_end) {
+ object_id = BE_16(buf);
+ buf += 2;
+
+ object = get_object(ctx, object_id);
+
+ if (object == NULL) {
+ object = av_mallocz(sizeof(DVBSubObject));
+
+ object->id = object_id;
+ object->next = ctx->object_list;
+ ctx->object_list = object;
+ }
+
+ object->type = (*buf) >> 6;
+
+ display = av_mallocz(sizeof(DVBSubObjectDisplay));
+
+ display->object_id = object_id;
+ display->region_id = region_id;
+
+ display->x_pos = BE_16(buf) & 0xfff;
+ buf += 2;
+ display->y_pos = BE_16(buf) & 0xfff;
+ buf += 2;
+
+ if ((object->type == 1 || object->type == 2) && buf+1 < buf_end) {
+ display->fgcolour = *buf++;
+ display->bgcolour = *buf++;
+ }
+
+ display->region_list_next = region->display_list;
+ region->display_list = display;
+
+ display->object_list_next = object->display_list;
+ object->display_list = display;
+ }
+}
+
+static void dvbsub_parse_page_segment(AVCodecContext *avctx,
+ uint8_t *buf, int buf_size)
+{
+ DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data;
+ DVBSubRegionDisplay *display;
+ DVBSubRegionDisplay *tmp_display_list, **tmp_ptr;
+
+ uint8_t *buf_end = buf + buf_size;
+ int region_id;
+ int page_state;
+
+ if (buf_size < 1)
+ return;
+
+ ctx->time_out = *buf++;
+ page_state = ((*buf++) >> 2) & 3;
+
+#ifdef DEBUG
+ av_log(avctx, AV_LOG_INFO, "Page time out %ds, state %d\n", ctx->time_out, page_state);
+#endif
+
+ if (page_state == 2)
+ {
+ delete_state(ctx);
+ }
+
+ tmp_display_list = ctx->display_list;
+ ctx->display_list = NULL;
+ ctx->display_list_size = 0;
+
+ while (buf + 5 < buf_end) {
+ region_id = *buf++;
+ buf += 1;
+
+ display = tmp_display_list;
+ tmp_ptr = &tmp_display_list;
+
+ while (display != NULL && display->region_id != region_id) {
+ tmp_ptr = &display->next;
+ display = display->next;
+ }
+
+ if (display == NULL)
+ display = av_mallocz(sizeof(DVBSubRegionDisplay));
+
+ display->region_id = region_id;
+
+ display->x_pos = BE_16(buf);
+ buf += 2;
+ display->y_pos = BE_16(buf);
+ buf += 2;
+
+ *tmp_ptr = display->next;
+
+ display->next = ctx->display_list;
+ ctx->display_list = display;
+ ctx->display_list_size++;
+
+#ifdef DEBUG
+ av_log(avctx, AV_LOG_INFO, "Region %d, (%d,%d)\n", region_id, display->x_pos, display->y_pos);
+#endif
+ }
+
+ while (tmp_display_list != 0) {
+ display = tmp_display_list;
+
+ tmp_display_list = display->next;
+
+ av_free(display);
+ }
+
+}
+
+
+#ifdef DEBUG_SAVE_IMAGES
+static void save_display_set(DVBSubContext *ctx)
+{
+ DVBSubRegion *region;
+ DVBSubRegionDisplay *display;
+ DVBSubCLUT *clut;
+ uint32_t *clut_table;
+ int x_pos, y_pos, width, height;
+ int x, y, y_off, x_off;
+ uint32_t *pbuf;
+ char filename[32];
+ static int fileno_index = 0;
+
+ x_pos = -1;
+ y_pos = -1;
+ width = 0;
+ height = 0;
+
+ for (display = ctx->display_list; display != NULL; display = display->next) {
+ region = get_region(ctx, display->region_id);
+
+ if (x_pos == -1) {
+ x_pos = display->x_pos;
+ y_pos = display->y_pos;
+ width = region->width;
+ height = region->height;
+ } else {
+ if (display->x_pos < x_pos) {
+ width += (x_pos - display->x_pos);
+ x_pos = display->x_pos;
+ }
+
+ if (display->y_pos < y_pos) {
+ height += (y_pos - display->y_pos);
+ y_pos = display->y_pos;
+ }
+
+ if (display->x_pos + region->width > x_pos + width) {
+ width = display->x_pos + region->width - x_pos;
+ }
+
+ if (display->y_pos + region->height > y_pos + height) {
+ height = display->y_pos + region->height - y_pos;
+ }
+ }
+ }
+
+ if (x_pos >= 0) {
+
+ pbuf = av_malloc(width * height * 4);
+
+ for (display = ctx->display_list; display != NULL; display = display->next) {
+ region = get_region(ctx, display->region_id);
+
+ x_off = display->x_pos - x_pos;
+ y_off = display->y_pos - y_pos;
+
+ clut = get_clut(ctx, region->clut);
+
+ if (clut == 0)
+ clut = &default_clut;
+
+ switch (region->depth) {
+ case 2:
+ clut_table = clut->clut4;
+ break;
+ case 8:
+ clut_table = clut->clut256;
+ break;
+ case 4:
+ default:
+ clut_table = clut->clut16;
+ break;
+ }
+
+ for (y = 0; y < region->height; y++) {
+ for (x = 0; x < region->width; x++) {
+ pbuf[((y + y_off) * width) + x_off + x] =
+ clut_table[region->pbuf[y * region->width + x]];
+ }
+ }
+
+ }
+
+ snprintf(filename, 32, "dvbs.%d", fileno_index);
+
+ png_save2(filename, pbuf, width, height);
+
+ av_free(pbuf);
+ }
+
+ fileno_index++;
+}
+#endif
+
+static int dvbsub_display_end_segment(AVCodecContext *avctx, uint8_t *buf,
+ int buf_size, AVSubtitle *sub)
+{
+ DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data;
+
+ DVBSubRegion *region;
+ DVBSubRegionDisplay *display;
+ AVSubtitleRect *rect;
+ DVBSubCLUT *clut;
+ uint32_t *clut_table;
+ int i;
+
+ sub->rects = NULL;
+ sub->start_display_time = 0;
+ sub->end_display_time = ctx->time_out * 1000;
+ sub->format = 0;
+
+ sub->num_rects = ctx->display_list_size;
+
+ if (sub->num_rects == 0)
+ return 0;
+
+ sub->rects = av_mallocz(sizeof(AVSubtitleRect) * sub->num_rects);
+
+ i = 0;
+
+ for (display = ctx->display_list; display != NULL; display = display->next) {
+ region = get_region(ctx, display->region_id);
+ rect = &sub->rects[i];
+
+ if (region == NULL)
+ continue;
+
+ rect->x = display->x_pos;
+ rect->y = display->y_pos;
+ rect->w = region->width;
+ rect->h = region->height;
+ rect->nb_colors = 16;
+ rect->linesize = region->width;
+
+ clut = get_clut(ctx, region->clut);
+
+ if (clut == NULL)
+ clut = &default_clut;
+
+ switch (region->depth) {
+ case 2:
+ clut_table = clut->clut4;
+ break;
+ case 8:
+ clut_table = clut->clut256;
+ break;
+ case 4:
+ default:
+ clut_table = clut->clut16;
+ break;
+ }
+
+ rect->rgba_palette = av_malloc((1 << region->depth) * sizeof(uint32_t));
+ memcpy(rect->rgba_palette, clut_table, (1 << region->depth) * sizeof(uint32_t));
+
+ rect->bitmap = av_malloc(region->buf_size);
+ memcpy(rect->bitmap, region->pbuf, region->buf_size);
+
+ i++;
+ }
+
+ sub->num_rects = i;
+
+#ifdef DEBUG_SAVE_IMAGES
+ save_display_set(ctx);
+#endif
+
+ return 1;
+}
+
+static int dvbsub_decode(AVCodecContext *avctx,
+ void *data, int *data_size,
+ uint8_t *buf, int buf_size)
+{
+ DVBSubContext *ctx = (DVBSubContext*) avctx->priv_data;
+ AVSubtitle *sub = (AVSubtitle*) data;
+ uint8_t *p, *p_end;
+ int segment_type;
+ int page_id;
+ int segment_length;
+
+#ifdef DEBUG_PACKET_CONTENTS
+ int i;
+
+ av_log(avctx, AV_LOG_INFO, "DVB sub packet:\n");
+
+ for (i=0; i < buf_size; i++)
+ {
+ av_log(avctx, AV_LOG_INFO, "%02x ", buf[i]);
+ if (i % 16 == 15)
+ av_log(avctx, AV_LOG_INFO, "\n");
+ }
+
+ if (i % 16 != 0)
+ av_log(avctx, AV_LOG_INFO, "\n");
+
+#endif
+
+ if (buf_size <= 2)
+ return -1;
+
+ p = buf;
+ p_end = buf + buf_size;
+
+ while (p < p_end && *p == 0x0f)
+ {
+ p += 1;
+ segment_type = *p++;
+ page_id = BE_16(p);
+ p += 2;
+ segment_length = BE_16(p);
+ p += 2;
+
+ if (page_id == ctx->composition_id || page_id == ctx->ancillary_id) {
+ switch (segment_type) {
+ case DVBSUB_PAGE_SEGMENT:
+ dvbsub_parse_page_segment(avctx, p, segment_length);
+ break;
+ case DVBSUB_REGION_SEGMENT:
+ dvbsub_parse_region_segment(avctx, p, segment_length);
+ break;
+ case DVBSUB_CLUT_SEGMENT:
+ dvbsub_parse_clut_segment(avctx, p, segment_length);
+ break;
+ case DVBSUB_OBJECT_SEGMENT:
+ dvbsub_parse_object_segment(avctx, p, segment_length);
+ break;
+ case DVBSUB_DISPLAY_SEGMENT:
+ *data_size = dvbsub_display_end_segment(avctx, p, segment_length, sub);
+ break;
+ default:
+#ifdef DEBUG
+ av_log(avctx, AV_LOG_INFO, "Subtitling segment type 0x%x, page id %d, length %d\n",
+ segment_type, page_id, segment_length);
+#endif
+ break;
+ }
+ }
+
+ p += segment_length;
+ }
+
+ if (p != p_end)
+ {
+#ifdef DEBUG
+ av_log(avctx, AV_LOG_INFO, "Junk at end of packet\n");
+#endif
+ return -1;
+ }
+
+ return 0;
+}
+
+
+AVCodec dvbsub_decoder = {
+ "dvbsub",
+ CODEC_TYPE_SUBTITLE,
+ CODEC_ID_DVB_SUBTITLE,
+ sizeof(DVBSubContext),
+ dvbsub_init_decoder,
+ NULL,
+ dvbsub_close_decoder,
+ dvbsub_decode,
+};
+
+/* Parser (mostly) copied from dvdsub.c */
+
+#define PARSE_BUF_SIZE (65536)
+
+
+/* parser definition */
+typedef struct DVBSubParseContext {
+ uint8_t *packet_buf;
+ int packet_start;
+ int packet_index;
+ int in_packet;
+} DVBSubParseContext;
+
+static int dvbsub_parse_init(AVCodecParserContext *s)
+{
+ DVBSubParseContext *pc = s->priv_data;
+ pc->packet_buf = av_malloc(PARSE_BUF_SIZE);
+
+ return 0;
+}
+
+static int dvbsub_parse(AVCodecParserContext *s,
+ AVCodecContext *avctx,
+ uint8_t **poutbuf, int *poutbuf_size,
+ const uint8_t *buf, int buf_size)
+{
+ DVBSubParseContext *pc = s->priv_data;
+ uint8_t *p, *p_end;
+ int len, buf_pos = 0;
+
+#ifdef DEBUG
+ av_log(avctx, AV_LOG_INFO, "DVB parse packet pts=%Lx, lpts=%Lx, cpts=%Lx:\n",
+ s->pts, s->last_pts, s->cur_frame_pts[s->cur_frame_start_index]);
+#endif
+
+#ifdef DEBUG_PACKET_CONTENTS
+ int i;
+
+ for (i=0; i < buf_size; i++)
+ {
+ av_log(avctx, AV_LOG_INFO, "%02x ", buf[i]);
+ if (i % 16 == 15)
+ av_log(avctx, AV_LOG_INFO, "\n");
+ }
+
+ if (i % 16 != 0)
+ av_log(avctx, AV_LOG_INFO, "\n");
+
+#endif
+
+ *poutbuf = NULL;
+ *poutbuf_size = 0;
+
+ s->fetch_timestamp = 1;
+
+ if (s->last_pts != s->pts && s->last_pts != AV_NOPTS_VALUE) /* Start of a new packet */
+ {
+ if (pc->packet_index != pc->packet_start)
+ {
+#ifdef DEBUG
+ av_log(avctx, AV_LOG_INFO, "Discarding %d bytes\n",
+ pc->packet_index - pc->packet_start);
+#endif
+ }
+
+ pc->packet_start = 0;
+ pc->packet_index = 0;
+
+ if (buf_size < 2 || buf[0] != 0x20 || buf[1] != 0x00) {
+#ifdef DEBUG
+ av_log(avctx, AV_LOG_INFO, "Bad packet header\n");
+#endif
+ return -1;
+ }
+
+ buf_pos = 2;
+
+ pc->in_packet = 1;
+ } else {
+ if (pc->packet_start != 0)
+ {
+ if (pc->packet_index != pc->packet_start)
+ {
+ memmove(pc->packet_buf, pc->packet_buf + pc->packet_start,
+ pc->packet_index - pc->packet_start);
+
+ pc->packet_index -= pc->packet_start;
+ pc->packet_start = 0;
+ } else {
+ pc->packet_start = 0;
+ pc->packet_index = 0;
+ }
+ }
+ }
+
+ if (buf_size - buf_pos + pc->packet_index > PARSE_BUF_SIZE)
+ return -1;
+
+/* if not currently in a packet, discard data */
+ if (pc->in_packet == 0)
+ return buf_size;
+
+ memcpy(pc->packet_buf + pc->packet_index, buf + buf_pos, buf_size - buf_pos);
+ pc->packet_index += buf_size - buf_pos;
+
+ p = pc->packet_buf;
+ p_end = pc->packet_buf + pc->packet_index;
+
+ while (p < p_end)
+ {
+ if (*p == 0x0f)
+ {
+ if (p + 6 <= p_end)
+ {
+ len = BE_16(p + 4);
+
+ if (p + len + 6 <= p_end)
+ {
+ *poutbuf_size += len + 6;
+
+ p += len + 6;
+ } else
+ break;
+ } else
+ break;
+ } else if (*p == 0xff) {
+ if (p + 1 < p_end)
+ {
+#ifdef DEBUG
+ av_log(avctx, AV_LOG_INFO, "Junk at end of packet\n");
+#endif
+ }
+ pc->packet_index = p - pc->packet_buf;
+ pc->in_packet = 0;
+ break;
+ } else {
+ av_log(avctx, AV_LOG_ERROR, "Junk in packet\n");
+
+ pc->packet_index = p - pc->packet_buf;
+ pc->in_packet = 0;
+ break;
+ }
+ }
+
+ if (*poutbuf_size > 0)
+ {
+ *poutbuf = pc->packet_buf;
+ pc->packet_start = *poutbuf_size;
+ }
+
+ if (s->last_pts == AV_NOPTS_VALUE)
+ s->last_pts = s->pts;
+
+ return buf_size;
+}
+
+static void dvbsub_parse_close(AVCodecParserContext *s)
+{
+ DVBSubParseContext *pc = s->priv_data;
+ av_freep(&pc->packet_buf);
+}
+
+AVCodecParser dvbsub_parser = {
+ { CODEC_ID_DVB_SUBTITLE },
+ sizeof(DVBSubParseContext),
+ dvbsub_parse_init,
+ dvbsub_parse,
+ dvbsub_parse_close,
+};