[FFmpeg-devel] [PATCH] DVBSUBTILES, fixes to decoding/encoding and a new way of burning the subtitles onto the screen

Clément Bœsch ubitux at gmail.com
Sun Sep 25 00:18:20 CEST 2011


From: joolzg <joolzg at btinternet.com>

---
Here is the second patch from Julian Gardner.

I did my best to remove the unrelated changes, fix the style and various other
things, but it's still far from perfect. Some real reviews are needed.

This patch includes various changes that might be splitted and explained. Also,
there is a pretty big hack in ffmpeg.c that should be fixed.
---
 ffmpeg.c               |  264 +++++++++++++++++++++++++++++++++++++----------
 libavcodec/avcodec.h   |    2 +
 libavcodec/dvbsub.c    |  199 ++++++++++++++++++++++++------------
 libavcodec/dvbsubdec.c |  249 +++++++++++++++++++++++++++++----------------
 libavcodec/utils.c     |    4 -
 5 files changed, 505 insertions(+), 213 deletions(-)

diff --git a/ffmpeg.c b/ffmpeg.c
index 6da97d2..9d0f721 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -162,6 +162,21 @@ static uint8_t *audio_out;
 static unsigned int allocated_audio_out_size, allocated_audio_buf_size;
 
 static short *samples;
+
+static AVBitStreamFilterContext *video_bitstream_filters;
+static AVBitStreamFilterContext *audio_bitstream_filters;
+static AVBitStreamFilterContext *subtitle_bitstream_filters;
+
+#define DEBUG_SUBS                  0
+#define DEBUG_SUBS2                 0
+#define NUMBER_OF_SUB_FIFO_ENTRIES  16
+static int64_t    start_time;
+static int        hard_subtitles = 0;
+static AVSubtitle subtitle__,
+                  current_subtitle,
+                  fifo_subtitle[NUMBER_OF_SUB_FIFO_ENTRIES];
+static int        fifo_subtitle_cnt;
+
 static uint8_t *input_tmp= NULL;
 
 #define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass"
@@ -1032,9 +1047,10 @@ static void pre_process_video_frame(InputStream *ist, AVPicture *picture, void *
 
     dec = ist->st->codec;
 
-    /* deinterlace : must be done before any resize */
-    if (do_deinterlace) {
+    /* deinterlace or hard subtitles : must be done before any resize */
+    if (do_deinterlace || hard_subtitles) {
         int size;
+        int error = 0;
 
         /* create temporary picture */
         size = avpicture_get_size(dec->pix_fmt, dec->width, dec->height);
@@ -1044,13 +1060,127 @@ static void pre_process_video_frame(InputStream *ist, AVPicture *picture, void *
 
         picture2 = &picture_tmp;
         avpicture_fill(picture2, buf, dec->pix_fmt, dec->width, dec->height);
+        if (do_deinterlace)
+            error = avpicture_deinterlace(picture2, picture, dec->pix_fmt,
+                                          dec->width, dec->height);
+        else
+            av_picture_copy(picture2, picture, dec->pix_fmt, dec->width,
+                            dec->height);
+
+        if (!(error < 0) && hard_subtitles) {
+            if (DEBUG_SUBS && fifo_subtitle_cnt) {
+                fprintf(stderr, "VideoFrame %ld %d:[%ld%ld%ld%ld%ld%ld%ld%ld%ld] %d %dx%d\r\n", (long int)ist->pts,
+                        fifo_subtitle_cnt,
+                        (long int)(current_subtitle.valid ? 1 : 0),
+                        (long int)(fifo_subtitle[0].valid ? 1 : 0),
+                        (long int)(fifo_subtitle[1].valid ? 1 : 0),
+                        (long int)(fifo_subtitle[2].valid ? 1 : 0),
+                        (long int)(fifo_subtitle[3].valid ? 1 : 0),
+                        (long int)(fifo_subtitle[4].valid ? 1 : 0),
+                        (long int)(fifo_subtitle[5].valid ? 1 : 0),
+                        (long int)(fifo_subtitle[6].valid ? 1 : 0),
+                        (long int)(fifo_subtitle[7].valid ? 1 : 0),
+                        dec->pix_fmt, dec->width, dec->height);
+            }
+
+//            if (current_subtitle.valid && ist>=current_subtitle.pts_end) {
+//                avsubtitle_free(&current_subtitle);
+//                current_subtitle.valid = 0;
+//            }
+
+            if (fifo_subtitle[0].valid) {
+                if (ist->pts>fifo_subtitle[0].pts) {
+                    int l;
+                    if (current_subtitle.valid)
+                        avsubtitle_free(&current_subtitle);
+                    current_subtitle = fifo_subtitle[0];
+                    for (l = 0; l < NUMBER_OF_SUB_FIFO_ENTRIES-1 ; l++)
+                        fifo_subtitle[l] = fifo_subtitle[l+1];
+                    fifo_subtitle[NUMBER_OF_SUB_FIFO_ENTRIES-1].valid = 0;
+                    fifo_subtitle_cnt--;
+                }
+            }
+
+            if (current_subtitle.valid && ist->pts>=current_subtitle.pts) {
+                int l, m, n;
+                int xp = 0, yp = 0, xo = 0, yo = 0;
+
+                for (l = 0; l < current_subtitle.num_rects; l++) {
+                    xp = FFMAX(xp,current_subtitle.rects[l]->x+current_subtitle.rects[l]->w);
+                    yp = FFMAX(yp,current_subtitle.rects[l]->y+current_subtitle.rects[l]->h);
+                }
+
+                if (xp >= dec->width)  xo = -xp-dec->width;
+                if (yp >= dec->height) yo = -yp-dec->height;
+
+                if (DEBUG_SUBS && current_subtitle.num_rects)
+                    fprintf( stderr, "Subs %d:", current_subtitle.num_rects);
+
+                for (l = 0; l < current_subtitle.num_rects; l++) {
+                    uint8_t *p[4];
+                    uint8_t *s;
+
+                    xp = current_subtitle.rects[l]->x+xo;
+                    yp = current_subtitle.rects[l]->y+yo;
+
+                    if (DEBUG_SUBS)
+                        fprintf(stderr, "[%d,%d %dx%d]", xp, yp,
+                                current_subtitle.rects[l]->w, current_subtitle.rects[l]->h);
+
+                    p[0]  = picture2->data[0];
+                    p[0] += yp*picture2->linesize[0];
+                    p[0] += xp;
+                    for (n = 1; n < 3; n++) {
+                        p[n]  = picture2->data[n];
+                        p[n] += (yp >> 1) * picture2->linesize[n];
+                        p[n] +=  xp >> 1;
+                    }
+                    s = current_subtitle.rects[l]->pict.data[0];
+
+                    for (m = 0; m < current_subtitle.rects[l]->h; m++) {
+                        if (m+yp < dec->height) {
+                            for (n = 0; n < current_subtitle.rects[l]->w; n++) {
+                                if (n+xp < dec->width) {
+                                    uint8_t pixel;
+                                    uint8_t Y, U, V;
+                                    uint8_t R, G, B, A;
+                                    uint32_t x;
+                                    double  alpha;
+
+                                    pixel = s[n];
+                                    x = ((uint32_t *)current_subtitle.rects[l]->pict.data[1])[pixel];
+                                    A = (x>>24) & 255;
+                                    R = (x>>16) & 255;
+                                    G = (x>>8 ) & 255;
+                                    B = (x>>0 ) & 255;
+                                    alpha = (double)A/255.0;
+
+                                    Y = RGB_TO_Y_CCIR(R, G, B);
+                                    U = RGB_TO_U_CCIR(R, G, B, 0);
+                                    V = RGB_TO_V_CCIR(R, G, B, 0);
+                                    p[0][n]    = (1.0-alpha)*p[0][n]    + alpha*Y;
+                                    p[1][n>>1] = (1.0-alpha)*p[1][n>>1] + alpha*U;
+                                    p[2][n>>1] = (1.0-alpha)*p[2][n>>1] + alpha*V;
+                                }
+                            }
+                            p[0] += picture2->linesize[0];
+                            if ((m+yp) & 1)
+                                for (n = 1; n < 3; n++)
+                                    p[n] += picture2->linesize[n];
+                            s += current_subtitle.rects[l]->pict.linesize[0];
+                        }
+                    }
+                }
+                if (DEBUG_SUBS)
+                    fprintf(stderr, "\n");
+            }
+            error = 0;
+        }
 
-        if(avpicture_deinterlace(picture2, picture,
-                                 dec->pix_fmt, dec->width, dec->height) < 0) {
+        if (error < 0) {
             /* if error, do not deinterlace */
             fprintf(stderr, "Deinterlacing failed\n");
-            av_free(buf);
-            buf = NULL;
+            av_freep(&buf);
             picture2 = picture;
         }
     } else {
@@ -1070,7 +1200,7 @@ static void do_subtitle_out(AVFormatContext *s,
 {
     static uint8_t *subtitle_out = NULL;
     int subtitle_out_max_size = 1024 * 1024;
-    int subtitle_out_size, nb, i;
+    int subtitle_out_size;
     AVCodecContext *enc;
     AVPacket pkt;
 
@@ -1083,46 +1213,66 @@ static void do_subtitle_out(AVFormatContext *s,
 
     enc = ost->st->codec;
 
-    if (!subtitle_out) {
-        subtitle_out = av_malloc(subtitle_out_max_size);
-    }
+        sub->pts = av_rescale_q(pts, ist->st->time_base, AV_TIME_BASE_Q);
+        sub->pts_end = sub->pts;
+        sub->pts_end += av_rescale_q(sub->end_display_time,
+                                     (AVRational){1, 1000}, AV_TIME_BASE_Q);
 
-    /* Note: DVB subtitle need one packet to draw them and one other
-       packet to clear them */
-    /* XXX: signal it in the codec context ? */
-    if (enc->codec_id == CODEC_ID_DVB_SUBTITLE)
-        nb = 2;
-    else
-        nb = 1;
+#if DEBUG_SUBS2
+        fprintf(stderr, "Do Subtitle Out start:%ld end:%ld\n",
+                (long int)sub->pts, (long int)sub->pts_end);
+#endif
 
-    for(i = 0; i < nb; i++) {
-        sub->pts = av_rescale_q(pts, ist->st->time_base, AV_TIME_BASE_Q);
-        // start_display_time is required to be 0
-        sub->pts              += av_rescale_q(sub->start_display_time, (AVRational){1, 1000}, AV_TIME_BASE_Q);
-        sub->end_display_time -= sub->start_display_time;
-        sub->start_display_time = 0;
-        subtitle_out_size = avcodec_encode_subtitle(enc, subtitle_out,
-                                                    subtitle_out_max_size, sub);
-        if (subtitle_out_size < 0) {
-            fprintf(stderr, "Subtitle encoding failed\n");
-            exit_program(1);
+        if (!subtitle_out) {
+            subtitle_out = av_malloc(subtitle_out_max_size);
         }
 
-        av_init_packet(&pkt);
-        pkt.stream_index = ost->index;
-        pkt.data = subtitle_out;
-        pkt.size = subtitle_out_size;
-        pkt.pts = av_rescale_q(sub->pts, AV_TIME_BASE_Q, ost->st->time_base);
-        if (enc->codec_id == CODEC_ID_DVB_SUBTITLE) {
-            /* XXX: the pts correction is handled here. Maybe handling
-               it in the codec would be better */
-            if (i == 0)
-                pkt.pts += 90 * sub->start_display_time;
-            else
-                pkt.pts += 90 * sub->end_display_time;
+        enc->width  = 720; // frame_width;
+        enc->height = 576; // frame_height;
+        if (hard_subtitles) {
+            subtitle_out_size = 0;
+            if (fifo_subtitle_cnt < NUMBER_OF_SUB_FIFO_ENTRIES) {
+                fifo_subtitle[fifo_subtitle_cnt] = *sub;
+                fifo_subtitle_cnt++;
+                sub->valid = 0;
+            } else {
+                av_log(s, AV_LOG_ERROR, "Hard Subtitles FIFO Full\n");
+                avsubtitle_free( sub);
+            }
+        } else if (hard_subtitles) {
+            int nbr = sub->num_rects;
+            // The following **HACK** makes it so that the subtitle engine produces
+            // an empty packet devoid of rectangles as this is the only way i can
+            // find to keep ffmpeg happy with its bitrate system
+            sub->num_rects = 0;
+            subtitle_out_size = avcodec_encode_subtitle(enc, subtitle_out,
+                    subtitle_out_max_size, sub);
+            sub->num_rects = nbr;
+            if (fifo_subtitle_cnt<NUMBER_OF_SUB_FIFO_ENTRIES) {
+                fifo_subtitle[fifo_subtitle_cnt] = *sub;
+                fifo_subtitle_cnt++;
+                sub->valid = 0;
+            } else {
+                av_log( s, AV_LOG_ERROR, "Hard Subtitles FIFO Full\n");
+                avsubtitle_free(sub);
+            }
+        } else {
+            subtitle_out_size = avcodec_encode_subtitle(enc, subtitle_out,
+                    subtitle_out_max_size,
+                    sub);
+
+            if (subtitle_out_size < 0)
+                av_log( s, AV_LOG_ERROR, "Subtitle encoding failed\n");
+            else if (subtitle_out_size) {
+                av_init_packet(&pkt);
+                pkt.stream_index = ost->index;
+                pkt.data = subtitle_out;
+                pkt.size = subtitle_out_size;
+                pkt.pts  = av_rescale_q(sub->pts, AV_TIME_BASE_Q, ost->st->time_base);
+                write_frame(s, &pkt, ost->st->codec, ost->bitstream_filters);
+            }
+            avsubtitle_free(sub);
         }
-        write_frame(s, &pkt, ost->st->codec, ost->bitstream_filters);
-    }
 }
 
 static int bit_buffer_size= 1024*256;
@@ -1459,6 +1609,7 @@ static void print_report(OutputFile *output_files,
             }
             vid = 1;
         }
+        if (!(enc->codec_type == AVMEDIA_TYPE_SUBTITLE && !subtitle__.valid))
         /* compute min output value */
         pts = FFMIN(pts, av_rescale_q(ost->st->pts.val,
                                       ost->st->time_base, AV_TIME_BASE_Q));
@@ -1610,7 +1761,6 @@ static int output_packet(InputStream *ist, int ist_index,
     AVFrame picture;
     void *buffer_to_free = NULL;
     static unsigned int samples_size= 0;
-    AVSubtitle subtitle, *subtitle_to_free;
     int64_t pkt_pts = AV_NOPTS_VALUE;
 #if CONFIG_AVFILTER
     int frame_available;
@@ -1656,7 +1806,6 @@ static int output_packet(InputStream *ist, int ist_index,
         decoded_data_size= 0;
         data_buf  = avpkt.data;
         data_size = avpkt.size;
-        subtitle_to_free = NULL;
         if (ist->decoding_needed) {
             switch(ist->st->codec->codec_type) {
             case AVMEDIA_TYPE_AUDIO:{
@@ -1715,14 +1864,23 @@ static int output_packet(InputStream *ist, int ist_index,
                     pre_process_video_frame(ist, (AVPicture *)&picture, &buffer_to_free);
                     break;
             case AVMEDIA_TYPE_SUBTITLE:
+//                fprintf(stderr, "Do subtitle in  start:%ld (%d)\n", ist->pts, subtitle__.valid);
+
+                if (subtitle__.valid) {
+                    fprintf(stderr, "Already have a Subtitle Video:%ld, Subtitle:%ld\r\n",
+                            (long int)ist->pts, (long int)subtitle__.pts);
+                    avsubtitle_free(&subtitle__);
+                }
+
                 ret = avcodec_decode_subtitle2(ist->st->codec,
-                                               &subtitle, &got_output, &avpkt);
+                                               &subtitle__, &got_output, &avpkt);
+
                 if (ret < 0)
                     return ret;
                 if (!got_output) {
                     goto discard_packet;
                 }
-                subtitle_to_free = &subtitle;
+                subtitle__.valid = 1;
                 avpkt.size = 0;
                 break;
             default:
@@ -1838,8 +1996,8 @@ static int output_packet(InputStream *ist, int ist_index,
                             do_video_stats(os, ost, frame_size);
                         break;
                     case AVMEDIA_TYPE_SUBTITLE:
-                        do_subtitle_out(os, ost, ist, &subtitle,
-                                        pkt->pts);
+                        if (subtitle__.valid)
+                            do_subtitle_out(os, ost, ist, &subtitle__, pkt->pts);
                         break;
                     default:
                         abort();
@@ -1848,8 +2006,7 @@ static int output_packet(InputStream *ist, int ist_index,
                     AVFrame avframe; //FIXME/XXX remove this
                     AVPicture pict;
                     AVPacket opkt;
-                    int64_t ost_tb_start_time= av_rescale_q(of->start_time, AV_TIME_BASE_Q, ost->st->time_base);
-                    av_init_packet(&opkt);
+                    int64_t ost_tb_start_time= av_rescale_q(start_time, AV_TIME_BASE_Q, ost->st->time_base);
 
                     if ((!ost->frame_number && !(pkt->flags & AV_PKT_FLAG_KEY)) && !copy_initial_nonkeyframes)
 #if !CONFIG_AVFILTER
@@ -1921,14 +2078,8 @@ static int output_packet(InputStream *ist, int ist_index,
         }
 
         av_free(buffer_to_free);
-        /* XXX: allocate the subtitles in the codec ? */
-        if (subtitle_to_free) {
-            avsubtitle_free(subtitle_to_free);
-            subtitle_to_free = NULL;
-        }
     }
  discard_packet:
-
     return 0;
 }
 
@@ -4274,6 +4425,7 @@ static const OptionDef options[] = {
     { "sn", OPT_BOOL | OPT_SUBTITLE | OPT_OFFSET, {.off = OFFSET(subtitle_disable)}, "disable subtitle" },
     { "scodec", HAS_ARG | OPT_SUBTITLE | OPT_FUNC2, {(void*)opt_subtitle_codec}, "force subtitle codec ('copy' to copy stream)", "codec" },
     { "stag", HAS_ARG | OPT_EXPERT | OPT_SUBTITLE | OPT_FUNC2, {(void*)opt_old2new}, "force subtitle tag/fourcc", "fourcc/tag" },
+    { "shard", OPT_BOOL | OPT_SUBTITLE, {(void*)&hard_subtitles}, "turn on burned in subtitles" },
 
     /* grab options */
     { "vc", HAS_ARG | OPT_EXPERT | OPT_VIDEO | OPT_GRAB, {(void*)opt_video_channel}, "deprecated, use -channel", "channel" },
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index e04513a..e5d3871 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -3219,12 +3219,14 @@ typedef struct AVSubtitleRect {
 } AVSubtitleRect;
 
 typedef struct AVSubtitle {
+    int valid;
     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
+    int64_t pts_end;
 } AVSubtitle;
 
 /* packet functions */
diff --git a/libavcodec/dvbsub.c b/libavcodec/dvbsub.c
index 2df8b58..8b28d06 100644
--- a/libavcodec/dvbsub.c
+++ b/libavcodec/dvbsub.c
@@ -22,9 +22,13 @@
 #include "bytestream.h"
 #include "libavutil/colorspace.h"
 
+//#define DEBUG
+
 typedef struct DVBSubtitleContext {
-    int hide_state;
+    int clut_version;
     int object_version;
+    int page_version;
+    int region_version;
 } DVBSubtitleContext;
 
 #define PUTBITS2(val)\
@@ -194,6 +198,61 @@ static void dvb_encode_rle4(uint8_t **pq,
     *pq = q;
 }
 
+static void dvb_encode_rle8(uint8_t **pq,
+                            const uint8_t *bitmap, int linesize,
+                            int w, int h)
+{
+    uint8_t *q;
+    int x, y, len, x1, f, color;
+
+    q = *pq;
+
+    for (y = 0; y < h; y++) {
+        *q++ = 0x12;
+
+        x = 0;
+        f = 0;
+        while (x < w) {
+            x1 = x;
+            color = bitmap[x1++];
+            while (x1 < w && bitmap[x1] == color)
+                x1++;
+            len = x1 - x;
+            if (len == 1 && color) {
+                // 00000001 to 11111111           1 pixel in colour x
+                *q++ = color;
+            } else {
+                if (color == 0x00) {
+                    // 00000000 0LLLLLLL          L pixels (1-127) in colour 0 (L > 0)
+                    len = FFMIN(len, 127);
+                    *q++ = 0x00;
+                    *q++ = len;
+                } else if (len > 2) {
+                    // 00000000 1LLLLLLL CCCCCCCC L pixels (3-127) in colour C (L > 2)
+                    len = FFMIN(len, 127);
+                    *q++ = 0x00;
+                    *q++ = 0x80+len;
+                    *q++ = color;
+                }
+                else if (len == 2) {
+                    *q++ = color;
+                    *q++ = color;
+                } else {
+                    *q++ = color;
+                    len = 1;
+                }
+            }
+            x += len;
+        }
+        /* end of line */
+        // 00000000 00000000 end of 8-bit/pixel_code_string
+        *q++ = 0x00;
+        *q++ = 0x00;
+        bitmap += linesize;
+    }
+    *pq = q;
+}
+
 static int encode_dvb_subtitles(DVBSubtitleContext *s,
                                 uint8_t *outbuf, AVSubtitle *h)
 {
@@ -205,9 +264,6 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s,
 
     page_id = 1;
 
-    if (h->num_rects == 0 || h->rects == NULL)
-        return -1;
-
     *q++ = 0x00; /* subtitle_stream_id */
 
     /* page composition segment */
@@ -218,12 +274,16 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s,
     pseg_len = q;
     q += 2; /* segment length */
     *q++ = 30; /* page_timeout (seconds) */
-    if (s->hide_state)
+    if (h->num_rects)
         page_state = 0; /* normal case */
     else
         page_state = 2; /* mode change */
+
+//    av_log( NULL, AV_LOG_WARNING, "Encode_dvb_subtitles %d regions\r\n", h->num_rects);
+
     /* page_version = 0 + page_state */
-    *q++ = (s->object_version << 4) | (page_state << 2) | 3;
+    *q++ = (s->page_version << 4) | (page_state << 2) | 3;
+    s->page_version = (s->page_version + 1) & 0xf;
 
     for (region_id = 0; region_id < h->num_rects; region_id++) {
         *q++ = region_id;
@@ -234,28 +294,75 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s,
 
     bytestream_put_be16(&pseg_len, q - pseg_len - 2);
 
-    if (!s->hide_state) {
-        for (clut_id = 0; clut_id < h->num_rects; clut_id++) {
+    if (!page_state) {
 
-            /* CLUT segment */
+        for (region_id = 0; region_id < h->num_rects; region_id++) {
+
+            /* bpp_index maths */
+            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 if (h->rects[region_id]->nb_colors <= 256) {
+                /* 8 bpp, standard encoding */
+                bpp_index = 2;
+            } else {
+                return -1;
+            }
 
+            /* region composition segment */
+            *q++ = 0x0f; /* sync_byte */
+            *q++ = 0x11; /* segment_type */
+            bytestream_put_be16(&q, page_id);
+            pseg_len = q;
+            q += 2; /* segment length */
+            *q++ = region_id;
+            *q++ = (s->region_version << 4) | (0 << 3) | 0x07; /* version , no fill */
+            s->region_version = (s->region_version + 1) & 15;
+            bytestream_put_be16(&q, h->rects[region_id]->w); /* region width */
+            bytestream_put_be16(&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 */
+
+            bytestream_put_be16(&q, region_id); /* object_id == region_id */
+            *q++ = (0 << 6) | (0 << 4);
+            *q++ = 0;
+            *q++ = 0xf0;
+            *q++ = 0;
+
+            bytestream_put_be16(&pseg_len, q - pseg_len - 2);
+        }
+
+        for (clut_id = 0; clut_id < h->num_rects; clut_id++) {
+
+            /* bpp_index maths */
             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 if (h->rects[clut_id]->nb_colors <= 256) {
+                /* 8 bpp, standard encoding */
+                bpp_index = 2;
             } else {
                 return -1;
             }
 
+
+            /* CLUT segment */
             *q++ = 0x0f; /* sync byte */
             *q++ = 0x12; /* CLUT definition segment */
             bytestream_put_be16(&q, page_id);
             pseg_len = q;
             q += 2; /* segment length */
             *q++ = clut_id;
-            *q++ = (0 << 4) | 0xf; /* version = 0 */
+            *q++ = (s->clut_version << 4) | 0xf; /* version = 0 */
+            s->clut_version = (s->clut_version + 1) & 0xf;
 
             for(i = 0; i < h->rects[clut_id]->nb_colors; i++) {
                 *q++ = i; /* clut_entry_id */
@@ -277,62 +384,27 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s,
 
             bytestream_put_be16(&pseg_len, q - pseg_len - 2);
         }
-    }
-
-    for (region_id = 0; region_id < h->num_rects; region_id++) {
-
-        /* region composition 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 */
-        bytestream_put_be16(&q, page_id);
-        pseg_len = q;
-        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 */
-        *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) {
-            bytestream_put_be16(&q, region_id); /* object_id == region_id */
-            *q++ = (0 << 6) | (0 << 4);
-            *q++ = 0;
-            *q++ = 0xf0;
-            *q++ = 0;
-        }
-
-        bytestream_put_be16(&pseg_len, q - pseg_len - 2);
-    }
-
-    if (!s->hide_state) {
 
         for (object_id = 0; object_id < h->num_rects; object_id++) {
-            /* Object Data segment */
+            void (*dvb_encode_rle)(uint8_t **pq,
+                                    const uint8_t *bitmap, int linesize,
+                                    int w, int h);
 
+            /* bpp_index maths */
             if (h->rects[object_id]->nb_colors <= 4) {
                 /* 2 bpp, some decoders do not support it correctly */
-                bpp_index = 0;
+                dvb_encode_rle = dvb_encode_rle2;
             } else if (h->rects[object_id]->nb_colors <= 16) {
                 /* 4 bpp, standard encoding */
-                bpp_index = 1;
+                dvb_encode_rle = dvb_encode_rle4;
+            } else if (h->rects[object_id]->nb_colors <= 256) {
+                /* 8 bpp, standard encoding */
+                dvb_encode_rle = dvb_encode_rle8;
             } else {
                 return -1;
             }
 
+            /* Object Data segment */
             *q++ = 0x0f; /* sync byte */
             *q++ = 0x13;
             bytestream_put_be16(&q, page_id);
@@ -343,21 +415,15 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s,
             *q++ = (s->object_version << 4) | (0 << 2) | (0 << 1) | 1; /* version = 0,
                                                                        onject_coding_method,
                                                                        non_modifying_color_flag */
+            s->object_version = (s->object_version + 1) & 0xf;
             {
                 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]->pict.data[0], h->rects[object_id]->w * 2,
                                     h->rects[object_id]->w, h->rects[object_id]->h >> 1);
@@ -386,8 +452,6 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s,
 
     *q++ = 0xff; /* end of PES data */
 
-    s->object_version = (s->object_version + 1) & 0xf;
-    s->hide_state = !s->hide_state;
     return q - outbuf;
 }
 
@@ -399,6 +463,11 @@ static int dvbsub_encode(AVCodecContext *avctx,
     int ret;
 
     ret = encode_dvb_subtitles(s, buf, sub);
+
+#ifdef DEBUG
+    av_log( avctx, AV_LOG_INFO, "dvbsub_encode %d bytes\r\n", ret);
+#endif
+
     return ret;
 }
 
diff --git a/libavcodec/dvbsubdec.c b/libavcodec/dvbsubdec.c
index ad213c8..53000d3 100644
--- a/libavcodec/dvbsubdec.c
+++ b/libavcodec/dvbsubdec.c
@@ -31,6 +31,8 @@
 #define DVBSUB_DISPLAYDEFINITION_SEGMENT 0x14
 #define DVBSUB_DISPLAY_SEGMENT  0x80
 
+//#define DEBUG
+
 #define cm (ff_cropTbl + MAX_NEG_CROP)
 
 #ifdef DEBUG
@@ -154,6 +156,7 @@ static void png_save2(const char *filename, uint32_t *bitmap, int w, int h)
 
 typedef struct DVBSubCLUT {
     int id;
+    int version;
 
     uint32_t clut4[4];
     uint32_t clut16[16];
@@ -180,6 +183,7 @@ typedef struct DVBSubObjectDisplay {
 
 typedef struct DVBSubObject {
     int id;
+    int version;
 
     int type;
 
@@ -199,6 +203,7 @@ typedef struct DVBSubRegionDisplay {
 
 typedef struct DVBSubRegion {
     int id;
+    int version;
 
     int width;
     int height;
@@ -209,6 +214,7 @@ typedef struct DVBSubRegion {
 
     uint8_t *pbuf;
     int buf_size;
+    int dirty;
 
     DVBSubObjectDisplay *display_list;
 
@@ -228,6 +234,7 @@ typedef struct DVBSubContext {
     int composition_id;
     int ancillary_id;
 
+    int version;
     int time_out;
     DVBSubRegion *region_list;
     DVBSubCLUT   *clut_list;
@@ -374,6 +381,8 @@ static av_cold int dvbsub_init_decoder(AVCodecContext *avctx)
         ctx->ancillary_id   = AV_RB16(avctx->extradata + 2);
     }
 
+    ctx->version = -1;
+
     default_clut.id = -1;
     default_clut.next = NULL;
 
@@ -462,16 +471,18 @@ static av_cold int dvbsub_close_decoder(AVCodecContext *avctx)
 
 static int dvbsub_read_2bit_string(uint8_t *destbuf, int dbuf_len,
                                    const uint8_t **srcbuf, int buf_size,
-                                   int non_mod, uint8_t *map_table)
+                                   int non_mod, uint8_t *map_table, int x_pos)
 {
     GetBitContext gb;
 
     int bits;
     int run_length;
-    int pixels_read = 0;
+    int pixels_read = x_pos;
 
     init_get_bits(&gb, *srcbuf, buf_size << 3);
 
+    destbuf += x_pos;
+
     while (get_bits_count(&gb) < buf_size << 3 && pixels_read < dbuf_len) {
         bits = get_bits(&gb, 2);
 
@@ -532,14 +543,14 @@ static int dvbsub_read_2bit_string(uint8_t *destbuf, int dbuf_len,
                             }
                         }
                     } else if (bits == 1) {
-                        pixels_read += 2;
                         if (map_table)
                             bits = map_table[0];
                         else
                             bits = 0;
-                        if (pixels_read <= dbuf_len) {
-                            *destbuf++ = bits;
+                        run_length = 2;
+                        while (run_length-- > 0 && pixels_read < dbuf_len) {
                             *destbuf++ = bits;
+                            pixels_read++;
                         }
                     } else {
                         (*srcbuf) += (get_bits_count(&gb) + 7) >> 3;
@@ -567,16 +578,23 @@ static int dvbsub_read_2bit_string(uint8_t *destbuf, int dbuf_len,
 
 static int dvbsub_read_4bit_string(uint8_t *destbuf, int dbuf_len,
                                    const uint8_t **srcbuf, int buf_size,
-                                   int non_mod, uint8_t *map_table)
+                                   int non_mod, uint8_t *map_table, int x_pos)
 {
     GetBitContext gb;
 
     int bits;
     int run_length;
-    int pixels_read = 0;
+    int pixels_read = x_pos;
 
     init_get_bits(&gb, *srcbuf, buf_size << 3);
 
+    destbuf += x_pos;
+
+#ifdef DEBUG
+    av_log(NULL, AV_LOG_WARNING, " in:dvbsub_read_4bit_string xpos:%d bufSize:%d pointer:%p\n", x_pos, dbuf_len, destbuf);
+    av_log(NULL, AV_LOG_WARNING, " in:dvbsub_read_4bit_string xpos:%d bufSize:%d\n", x_pos, dbuf_len);
+#endif
+
     while (get_bits_count(&gb) < buf_size << 3 && pixels_read < dbuf_len) {
         bits = get_bits(&gb, 4);
 
@@ -595,6 +613,9 @@ static int dvbsub_read_4bit_string(uint8_t *destbuf, int dbuf_len,
 
                 if (run_length == 0) {
                     (*srcbuf) += (get_bits_count(&gb) + 7) >> 3;
+#ifdef DEBUG
+                    av_log(NULL, AV_LOG_WARNING, "out:dvbsub_read_4bit_string xpos:%d bufSize:%d\n", pixels_read, dbuf_len);
+#endif
                     return pixels_read;
                 }
 
@@ -656,14 +677,14 @@ static int dvbsub_read_4bit_string(uint8_t *destbuf, int dbuf_len,
                             }
                         }
                     } else if (bits == 1) {
-                        pixels_read += 2;
                         if (map_table)
                             bits = map_table[0];
                         else
                             bits = 0;
-                        if (pixels_read <= dbuf_len) {
-                            *destbuf++ = bits;
+                        run_length = 2;
+                        while (run_length-- > 0 && pixels_read < dbuf_len) {
                             *destbuf++ = bits;
+                            pixels_read++;
                         }
                     } else {
                         if (map_table)
@@ -683,17 +704,23 @@ static int dvbsub_read_4bit_string(uint8_t *destbuf, int dbuf_len,
 
     (*srcbuf) += (get_bits_count(&gb) + 7) >> 3;
 
+#ifdef DEBUG
+    av_log(NULL, AV_LOG_WARNING, "out:dvbsub_read_4bit_string xpos:%d bufSize:%d\n", pixels_read, dbuf_len);
+#endif
+
     return pixels_read;
 }
 
 static int dvbsub_read_8bit_string(uint8_t *destbuf, int dbuf_len,
                                     const uint8_t **srcbuf, int buf_size,
-                                    int non_mod, uint8_t *map_table)
+                                    int non_mod, uint8_t *map_table, int x_pos)
 {
     const uint8_t *sbuf_end = (*srcbuf) + buf_size;
     int bits;
     int run_length;
-    int pixels_read = 0;
+    int pixels_read = x_pos;
+
+    destbuf += x_pos;
 
     while (*srcbuf < sbuf_end && pixels_read < dbuf_len) {
         bits = *(*srcbuf)++;
@@ -762,6 +789,7 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis
                          0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
     uint8_t *map_table;
 
+#if 0
     av_dlog(avctx, "DVB pixel block size %d, %s field:\n", buf_size,
             top_bottom ? "bottom" : "top");
 
@@ -776,21 +804,22 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis
 
     if (i % 16)
         av_dlog(avctx, "\n");
+#endif
 
     if (region == 0)
         return;
 
     pbuf = region->pbuf;
+    region->dirty = 1;
 
     x_pos = display->x_pos;
     y_pos = display->y_pos;
 
-    if ((y_pos & 1) != top_bottom)
-        y_pos++;
+    y_pos += top_bottom;
 
     while (buf < buf_end) {
-        if (x_pos > region->width || y_pos > region->height) {
-            av_log(avctx, AV_LOG_ERROR, "Invalid object location!\n");
+        if (*buf!=0xf0 && (x_pos >= region->width || y_pos >= region->height)) {
+            av_log(avctx, AV_LOG_ERROR, "Invalid object location! %d-%d %d-%d %02x\n", x_pos, region->width, y_pos, region->height, *buf);
             return;
         }
 
@@ -803,9 +832,9 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis
             else
                 map_table = NULL;
 
-            x_pos += dvbsub_read_2bit_string(pbuf + (y_pos * region->width) + x_pos,
-                                                region->width - x_pos, &buf, buf_end - buf,
-                                                non_mod, map_table);
+            x_pos = dvbsub_read_2bit_string(pbuf + (y_pos * region->width),
+                                            region->width, &buf, buf_end - buf,
+                                            non_mod, map_table, x_pos);
             break;
         case 0x11:
             if (region->depth < 4) {
@@ -818,9 +847,9 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis
             else
                 map_table = NULL;
 
-            x_pos += dvbsub_read_4bit_string(pbuf + (y_pos * region->width) + x_pos,
-                                                region->width - x_pos, &buf, buf_end - buf,
-                                                non_mod, map_table);
+            x_pos = dvbsub_read_4bit_string(pbuf + (y_pos * region->width),
+                                            region->width, &buf, buf_end - buf,
+                                            non_mod, map_table, x_pos);
             break;
         case 0x12:
             if (region->depth < 8) {
@@ -828,9 +857,9 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis
                 return;
             }
 
-            x_pos += dvbsub_read_8bit_string(pbuf + (y_pos * region->width) + x_pos,
-                                                region->width - x_pos, &buf, buf_end - buf,
-                                                non_mod, NULL);
+            x_pos = dvbsub_read_8bit_string(pbuf + (y_pos * region->width),
+                                            region->width, &buf, buf_end - buf,
+                                            non_mod, NULL, x_pos);
             break;
 
         case 0x20:
@@ -865,7 +894,6 @@ static void dvbsub_parse_object_segment(AVCodecContext *avctx,
     DVBSubContext *ctx = avctx->priv_data;
 
     const uint8_t *buf_end = buf + buf_size;
-    const uint8_t *block;
     int object_id;
     DVBSubObject *object;
     DVBSubObjectDisplay *display;
@@ -896,7 +924,12 @@ static void dvbsub_parse_object_segment(AVCodecContext *avctx,
         }
 
         for (display = object->display_list; display; display = display->object_list_next) {
-            block = buf;
+            const uint8_t *block = buf;
+            int bfl = bottom_field_len;
+
+#ifdef DEBUG
+            av_log(avctx, AV_LOG_WARNING, "  Object %d, Display %p, Block %p, Tfl %d, Bfl %d\n", object_id, display, block, top_field_len, bfl);
+#endif
 
             dvbsub_parse_pixel_data_block(avctx, display, block, top_field_len, 0,
                                             non_modifying_color);
@@ -904,9 +937,9 @@ static void dvbsub_parse_object_segment(AVCodecContext *avctx,
             if (bottom_field_len > 0)
                 block = buf + top_field_len;
             else
-                bottom_field_len = top_field_len;
+                bfl = top_field_len;
 
-            dvbsub_parse_pixel_data_block(avctx, display, block, bottom_field_len, 1,
+            dvbsub_parse_pixel_data_block(avctx, display, block, bfl, 1,
                                             non_modifying_color);
         }
 
@@ -923,8 +956,8 @@ static void dvbsub_parse_clut_segment(AVCodecContext *avctx,
 {
     DVBSubContext *ctx = avctx->priv_data;
 
-    const uint8_t *buf_end = buf + buf_size;
     int i, clut_id;
+    int version;
     DVBSubCLUT *clut;
     int entry_id, depth , full_range;
     int y, cr, cb, alpha;
@@ -942,7 +975,9 @@ static void dvbsub_parse_clut_segment(AVCodecContext *avctx,
         av_dlog(avctx, "\n");
 
     clut_id = *buf++;
+    version = ((*buf)>>4)&15;
     buf += 1;
+    buf_size -= 2;
 
     clut = get_clut(ctx, clut_id);
 
@@ -952,28 +987,37 @@ static void dvbsub_parse_clut_segment(AVCodecContext *avctx,
         memcpy(clut, &default_clut, sizeof(DVBSubCLUT));
 
         clut->id = clut_id;
+        clut->version = -1;
 
         clut->next = ctx->clut_list;
         ctx->clut_list = clut;
     }
 
-    while (buf + 4 < buf_end) {
+    if (clut->version != version) {
+
+    clut->version = version;
+
+    while (buf_size) {
         entry_id = *buf++;
+        buf_size--;
 
         depth = (*buf) & 0xe0;
 
         if (depth == 0) {
             av_log(avctx, AV_LOG_ERROR, "Invalid clut depth 0x%x!\n", *buf);
-            return;
+           return;
         }
 
         full_range = (*buf++) & 1;
+        buf_size--;
 
         if (full_range) {
             y = *buf++;
             cr = *buf++;
             cb = *buf++;
             alpha = *buf++;
+
+            buf_size -= 4;
         } else {
             y = buf[0] & 0xfc;
             cr = (((buf[0] & 3) << 2) | ((buf[1] >> 6) & 3)) << 4;
@@ -981,6 +1025,7 @@ static void dvbsub_parse_clut_segment(AVCodecContext *avctx,
             alpha = (buf[1] << 6) & 0xc0;
 
             buf += 2;
+            buf_size -= 2;
         }
 
         if (y == 0)
@@ -993,11 +1038,12 @@ static void dvbsub_parse_clut_segment(AVCodecContext *avctx,
 
         if (depth & 0x80)
             clut->clut4[entry_id] = RGBA(r,g,b,255 - alpha);
-        if (depth & 0x40)
+        else if (depth & 0x40)
             clut->clut16[entry_id] = RGBA(r,g,b,255 - alpha);
-        if (depth & 0x20)
+        else if (depth & 0x20)
             clut->clut256[entry_id] = RGBA(r,g,b,255 - alpha);
     }
+    }
 }
 
 
@@ -1008,15 +1054,14 @@ static void dvbsub_parse_region_segment(AVCodecContext *avctx,
 
     const uint8_t *buf_end = buf + buf_size;
     int region_id, object_id;
+    int version;
     DVBSubRegion *region;
     DVBSubObject *object;
     DVBSubObjectDisplay *display;
     int fill;
 
-    if (buf_size < 10)
-        return;
-
     region_id = *buf++;
+    buf_size--;
 
     region = get_region(ctx, region_id);
 
@@ -1024,17 +1069,22 @@ static void dvbsub_parse_region_segment(AVCodecContext *avctx,
         region = av_mallocz(sizeof(DVBSubRegion));
 
         region->id = region_id;
+        region->version = -1;
 
         region->next = ctx->region_list;
         ctx->region_list = region;
     }
 
+    version = ((*buf)>>4) & 15;
     fill = ((*buf++) >> 3) & 1;
+    buf_size--;
 
     region->width = AV_RB16(buf);
     buf += 2;
+    buf_size -= 2;
     region->height = AV_RB16(buf);
     buf += 2;
+    buf_size -= 2;
 
     if (region->width * region->height != region->buf_size) {
         av_free(region->pbuf);
@@ -1042,29 +1092,37 @@ static void dvbsub_parse_region_segment(AVCodecContext *avctx,
         region->buf_size = region->width * region->height;
 
         region->pbuf = av_malloc(region->buf_size);
-
-        fill = 1;
+        region->dirty = 0;
     }
 
     region->depth = 1 << (((*buf++) >> 2) & 7);
+    buf_size--;
     if(region->depth<2 || region->depth>8){
         av_log(avctx, AV_LOG_ERROR, "region depth %d is invalid\n", region->depth);
         region->depth= 4;
     }
     region->clut = *buf++;
+    buf_size--;
 
-    if (region->depth == 8)
+    if (region->depth == 8) {
         region->bgcolor = *buf++;
+        buf_size--;
+        buf += 1;
+        buf_size--;
+    }
     else {
         buf += 1;
+        buf_size--;
 
         if (region->depth == 4)
             region->bgcolor = (((*buf++) >> 4) & 15);
         else
             region->bgcolor = (((*buf++) >> 2) & 3);
+        buf_size--;
     }
 
     av_dlog(avctx, "Region %d, (%dx%d)\n", region_id, region->width, region->height);
+//  av_log(avctx, AV_LOG_WARNING, "  Region %d, (w:%d h:%d) %p to %p\n", region_id, region->width, region->height, region->pbuf, region->pbuf+region->buf_size);
 
     if (fill) {
         memset(region->pbuf, region->bgcolor, region->buf_size);
@@ -1073,9 +1131,10 @@ static void dvbsub_parse_region_segment(AVCodecContext *avctx,
 
     delete_region_display_list(ctx, region);
 
-    while (buf + 5 < buf_end) {
+    while (buf_size) {
         object_id = AV_RB16(buf);
         buf += 2;
+        buf_size -= 2;
 
         object = get_object(ctx, object_id);
 
@@ -1096,12 +1155,15 @@ static void dvbsub_parse_region_segment(AVCodecContext *avctx,
 
         display->x_pos = AV_RB16(buf) & 0xfff;
         buf += 2;
+        buf_size -= 2;
         display->y_pos = AV_RB16(buf) & 0xfff;
         buf += 2;
+        buf_size -= 2;
 
         if ((object->type == 1 || object->type == 2) && buf+1 < buf_end) {
             display->fgcolor = *buf++;
             display->bgcolor = *buf++;
+            buf_size -= 2;
         }
 
         display->region_list_next = region->display_list;
@@ -1109,6 +1171,10 @@ static void dvbsub_parse_region_segment(AVCodecContext *avctx,
 
         display->object_list_next = object->display_list;
         object->display_list = display;
+
+#ifdef DEBUG
+        av_log(avctx, AV_LOG_WARNING, "    Object %d, (x:%d y:%d)\n", object_id, display->x_pos, display->y_pos);
+#endif
     }
 }
 
@@ -1119,31 +1185,49 @@ static void dvbsub_parse_page_segment(AVCodecContext *avctx,
     DVBSubRegionDisplay *display;
     DVBSubRegionDisplay *tmp_display_list, **tmp_ptr;
 
-    const uint8_t *buf_end = buf + buf_size;
     int region_id;
     int page_state;
+    int version;
+    int timeout;
 
-    if (buf_size < 1)
-        return;
-
-    ctx->time_out = *buf++;
+    timeout = *buf++;
+    version = ((*buf)>>4) & 15;
     page_state = ((*buf++) >> 2) & 3;
+    buf_size -= 2;
+
+    if (ctx->version != version) {
+
+    ctx->time_out = timeout;
+    ctx->version = version;
 
     av_dlog(avctx, "Page time out %ds, state %d\n", ctx->time_out, page_state);
+#ifdef DEBUG
+    av_log(avctx, AV_LOG_WARNING, "dvbsub_parse_page_segment PageTimeOut:%d State:%d\n", ctx->time_out, page_state);
+#endif
 
-    if (page_state == 2) {
+    if (page_state == 1 || page_state == 2) {
         delete_regions(ctx);
         delete_objects(ctx);
         delete_cluts(ctx);
     }
 
     tmp_display_list = ctx->display_list;
+
+    while (tmp_display_list) {
+        display = tmp_display_list;
+
+        tmp_display_list = display->next;
+
+        av_free(display);
+    }
+
     ctx->display_list = NULL;
     ctx->display_list_size = 0;
 
-    while (buf + 5 < buf_end) {
+    while (buf_size) {
         region_id = *buf++;
         buf += 1;
+        buf_size -= 2;
 
         display = tmp_display_list;
         tmp_ptr = &tmp_display_list;
@@ -1160,8 +1244,10 @@ static void dvbsub_parse_page_segment(AVCodecContext *avctx,
 
         display->x_pos = AV_RB16(buf);
         buf += 2;
+        buf_size -= 2;
         display->y_pos = AV_RB16(buf);
         buf += 2;
+        buf_size -= 2;
 
         *tmp_ptr = display->next;
 
@@ -1170,16 +1256,11 @@ static void dvbsub_parse_page_segment(AVCodecContext *avctx,
         ctx->display_list_size++;
 
         av_dlog(avctx, "Region %d, (%d,%d)\n", region_id, display->x_pos, display->y_pos);
+#ifdef DEBUG
+        av_log(avctx, AV_LOG_WARNING, "  Region %d, (x:%d y:%d)\n", region_id, display->x_pos, display->y_pos);
+#endif
     }
-
-    while (tmp_display_list) {
-        display = tmp_display_list;
-
-        tmp_display_list = display->next;
-
-        av_free(display);
     }
-
 }
 
 
@@ -1286,9 +1367,6 @@ static void dvbsub_parse_display_definition_segment(AVCodecContext *avctx,
     DVBSubDisplayDefinition *display_def = ctx->display_definition;
     int dds_version, info_byte;
 
-    if (buf_size < 5)
-        return;
-
     info_byte   = bytestream_get_byte(&buf);
     dds_version = info_byte >> 4;
     if (display_def && display_def->version == dds_version)
@@ -1307,9 +1385,6 @@ static void dvbsub_parse_display_definition_segment(AVCodecContext *avctx,
     display_def->width   = bytestream_get_be16(&buf) + 1;
     display_def->height  = bytestream_get_be16(&buf) + 1;
 
-    if (buf_size < 13)
-        return;
-
     if (info_byte & 1<<3) { // display_window_flag
         display_def->x = bytestream_get_be16(&buf);
         display_def->y = bytestream_get_be16(&buf);
@@ -1328,7 +1403,6 @@ static int dvbsub_display_end_segment(AVCodecContext *avctx, const uint8_t *buf,
     DVBSubRegionDisplay *display;
     AVSubtitleRect *rect;
     DVBSubCLUT *clut;
-    uint32_t *clut_table;
     int i;
     int offset_x=0, offset_y=0;
 
@@ -1345,54 +1419,53 @@ static int dvbsub_display_end_segment(AVCodecContext *avctx, const uint8_t *buf,
         sub->rects = av_mallocz(sizeof(*sub->rects) * sub->num_rects);
         for(i=0; i<sub->num_rects; i++)
             sub->rects[i] = av_mallocz(sizeof(*sub->rects[i]));
-    }
 
     i = 0;
 
     for (display = ctx->display_list; display; display = display->next) {
         region = get_region(ctx, display->region_id);
-        rect = sub->rects[i];
 
         if (!region)
             continue;
 
+        if (!region->dirty)
+            continue;
+
+        rect = sub->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->pict.linesize[0] = region->width;
 
         clut = get_clut(ctx, region->clut);
-
         if (!clut)
             clut = &default_clut;
 
+        rect->pict.data[1] = av_mallocz(AVPALETTE_SIZE);
         switch (region->depth) {
         case 2:
-            clut_table = clut->clut4;
+            memcpy(rect->pict.data[1], clut->clut4, 4 * sizeof(uint32_t));
+            rect->nb_colors = 4;
             break;
         case 8:
-            clut_table = clut->clut256;
+            memcpy(rect->pict.data[1], clut->clut256, 256 * sizeof(uint32_t));
+            rect->nb_colors = 256;
             break;
         case 4:
         default:
-            clut_table = clut->clut16;
+            memcpy(rect->pict.data[1], clut->clut16, 16 * sizeof(uint32_t));
+            rect->nb_colors = 16;
             break;
         }
 
-        rect->pict.data[1] = av_mallocz(AVPALETTE_SIZE);
-        memcpy(rect->pict.data[1], clut_table, (1 << region->depth) * sizeof(uint32_t));
-
         rect->pict.data[0] = av_malloc(region->buf_size);
         memcpy(rect->pict.data[0], region->pbuf, region->buf_size);
-
         i++;
     }
-
     sub->num_rects = i;
-
+    }
 #ifdef DEBUG
     save_display_set(ctx);
 #endif
@@ -1408,12 +1481,13 @@ static int dvbsub_decode(AVCodecContext *avctx,
     int buf_size = avpkt->size;
     DVBSubContext *ctx = avctx->priv_data;
     AVSubtitle *sub = data;
-    const uint8_t *p, *p_end;
+    const uint8_t *p;
     int segment_type;
     int page_id;
     int segment_length;
     int i;
 
+#ifdef DEBUG
     av_dlog(avctx, "DVB sub packet:\n");
 
     for (i=0; i < buf_size; i++) {
@@ -1424,27 +1498,25 @@ static int dvbsub_decode(AVCodecContext *avctx,
 
     if (i % 16)
         av_dlog(avctx, "\n");
-
-    if (buf_size <= 6 || *buf != 0x0f) {
-        av_dlog(avctx, "incomplete or broken packet");
-        return -1;
-    }
+#endif
 
     p = buf;
-    p_end = buf + buf_size;
 
-    while (p_end - p >= 6 && *p == 0x0f) {
+    while (buf_size && *p == 0x0f) {
         p += 1;
         segment_type = *p++;
         page_id = AV_RB16(p);
         p += 2;
         segment_length = AV_RB16(p);
         p += 2;
+        buf_size -= 6;
 
-        if (p_end - p < segment_length) {
-            av_dlog(avctx, "incomplete or broken packet");
-            return -1;
-        }
+#ifdef DEBUG
+        av_log(avctx, AV_LOG_WARNING, "Process %02x %5d (%d)\r\n", segment_type, segment_length, buf_size);
+#endif
+
+        if (buf_size - segment_length < 0)
+            break;
 
         if (page_id == ctx->composition_id || page_id == ctx->ancillary_id ||
             ctx->composition_id == -1 || ctx->ancillary_id == -1) {
@@ -1475,6 +1547,7 @@ static int dvbsub_decode(AVCodecContext *avctx,
         }
 
         p += segment_length;
+        buf_size -= segment_length;
     }
 
     return p - buf;
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 95fb65a..bd99d7d 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -724,10 +724,6 @@ int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size,
                             const AVSubtitle *sub)
 {
     int ret;
-    if(sub->start_display_time) {
-        av_log(avctx, AV_LOG_ERROR, "start_display_time must be 0.\n");
-        return -1;
-    }
 
     ret = avctx->codec->encode(avctx, buf, buf_size, sub);
     avctx->frame_number++;
-- 
1.7.6.3



More information about the ffmpeg-devel mailing list