LCOV - code coverage report
Current view: top level - libavcodec - xsubenc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 91 0.0 %
Date: 2017-12-18 20:14:19 Functions: 0 5 0.0 %

          Line data    Source code
       1             : /*
       2             :  * DivX (XSUB) subtitle encoder
       3             :  * Copyright (c) 2005 DivX, Inc.
       4             :  * Copyright (c) 2009 Bjorn Axelsson
       5             :  *
       6             :  * This file is part of FFmpeg.
       7             :  *
       8             :  * FFmpeg is free software; you can redistribute it and/or
       9             :  * modify it under the terms of the GNU Lesser General Public
      10             :  * License as published by the Free Software Foundation; either
      11             :  * version 2.1 of the License, or (at your option) any later version.
      12             :  *
      13             :  * FFmpeg is distributed in the hope that it will be useful,
      14             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :  * Lesser General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU Lesser General Public
      19             :  * License along with FFmpeg; if not, write to the Free Software
      20             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      21             :  */
      22             : 
      23             : #include "avcodec.h"
      24             : #include "bytestream.h"
      25             : #include "put_bits.h"
      26             : 
      27             : /**
      28             :  * Number of pixels to pad left and right.
      29             :  *
      30             :  * The official encoder pads the subtitles with two pixels on either side,
      31             :  * but until we find out why, we won't do it (we will pad to have width
      32             :  * divisible by 2 though).
      33             :  */
      34             : #define PADDING 0
      35             : #define PADDING_COLOR 0
      36             : 
      37             : /**
      38             :  * Encode a single color run. At most 16 bits will be used.
      39             :  * @param len   length of the run, values > 255 mean "until end of line", may not be < 0.
      40             :  * @param color color to encode, only the lowest two bits are used and all others must be 0.
      41             :  */
      42           0 : static void put_xsub_rle(PutBitContext *pb, int len, int color)
      43             : {
      44           0 :     if (len <= 255)
      45           0 :         put_bits(pb, 2 + ((ff_log2_tab[len] >> 1) << 2), len);
      46             :     else
      47           0 :         put_bits(pb, 14, 0);
      48           0 :     put_bits(pb, 2, color);
      49           0 : }
      50             : 
      51             : /**
      52             :  * Encode a 4-color bitmap with XSUB rle.
      53             :  *
      54             :  * The encoded bitmap may be wider than the source bitmap due to padding.
      55             :  */
      56           0 : static int xsub_encode_rle(PutBitContext *pb, const uint8_t *bitmap,
      57             :                            int linesize, int w, int h)
      58             : {
      59           0 :     int x0, x1, y, len, color = PADDING_COLOR;
      60             : 
      61           0 :     for (y = 0; y < h; y++) {
      62           0 :         x0 = 0;
      63           0 :         while (x0 < w) {
      64             :             // Make sure we have enough room for at least one run and padding
      65           0 :             if (pb->size_in_bits - put_bits_count(pb) < 7*8)
      66           0 :                 return -1;
      67             : 
      68           0 :             x1 = x0;
      69           0 :             color = bitmap[x1++] & 3;
      70           0 :             while (x1 < w && (bitmap[x1] & 3) == color)
      71           0 :                 x1++;
      72           0 :             len = x1 - x0;
      73             :             if (PADDING && x0 == 0) {
      74             :                 if (color == PADDING_COLOR) {
      75             :                     len += PADDING;
      76             :                     x0  -= PADDING;
      77             :                 } else
      78             :                     put_xsub_rle(pb, PADDING, PADDING_COLOR);
      79             :             }
      80             : 
      81             :             // Run can't be longer than 255, unless it is the rest of a row
      82           0 :             if (x1 == w && color == PADDING_COLOR) {
      83           0 :                 len += PADDING + (w&1);
      84             :             } else
      85           0 :                 len = FFMIN(len, 255);
      86           0 :             put_xsub_rle(pb, len, color);
      87             : 
      88           0 :             x0 += len;
      89             :         }
      90           0 :         if (color != PADDING_COLOR && (PADDING + (w&1)))
      91           0 :             put_xsub_rle(pb, PADDING + (w&1), PADDING_COLOR);
      92             : 
      93           0 :         avpriv_align_put_bits(pb);
      94             : 
      95           0 :         bitmap += linesize;
      96             :     }
      97             : 
      98           0 :     return 0;
      99             : }
     100             : 
     101           0 : static int make_tc(uint64_t ms, int *tc)
     102             : {
     103             :     static const int tc_divs[3] = { 1000, 60, 60 };
     104             :     int i;
     105           0 :     for (i=0; i<3; i++) {
     106           0 :         tc[i] = ms % tc_divs[i];
     107           0 :         ms /= tc_divs[i];
     108             :     }
     109           0 :     tc[3] = ms;
     110           0 :     return ms > 99;
     111             : }
     112             : 
     113           0 : static int xsub_encode(AVCodecContext *avctx, unsigned char *buf,
     114             :                        int bufsize, const AVSubtitle *h)
     115             : {
     116           0 :     uint64_t startTime = h->pts / 1000; // FIXME: need better solution...
     117           0 :     uint64_t endTime = startTime + h->end_display_time - h->start_display_time;
     118             :     int start_tc[4], end_tc[4];
     119           0 :     uint8_t *hdr = buf + 27; // Point behind the timestamp
     120             :     uint8_t *rlelenptr;
     121             :     uint16_t width, height;
     122             :     int i;
     123             :     PutBitContext pb;
     124             : 
     125           0 :     if (bufsize < 27 + 7*2 + 4*3) {
     126           0 :         av_log(avctx, AV_LOG_ERROR, "Buffer too small for XSUB header.\n");
     127           0 :         return -1;
     128             :     }
     129             : 
     130             :     // TODO: support multiple rects
     131           0 :     if (h->num_rects != 1)
     132           0 :         av_log(avctx, AV_LOG_WARNING, "Only single rects supported (%d in subtitle.)\n", h->num_rects);
     133             : 
     134             : #if FF_API_AVPICTURE
     135             : FF_DISABLE_DEPRECATION_WARNINGS
     136           0 :     if (!h->rects[0]->data[0]) {
     137           0 :         AVSubtitleRect *rect = h->rects[0];
     138             :         int j;
     139           0 :         for (j = 0; j < 4; j++) {
     140           0 :             rect->data[j] = rect->pict.data[j];
     141           0 :             rect->linesize[j] = rect->pict.linesize[j];
     142             :         }
     143             :     }
     144             : FF_ENABLE_DEPRECATION_WARNINGS
     145             : #endif
     146             : 
     147             :     // TODO: render text-based subtitles into bitmaps
     148           0 :     if (!h->rects[0]->data[0] || !h->rects[0]->data[1]) {
     149           0 :         av_log(avctx, AV_LOG_WARNING, "No subtitle bitmap available.\n");
     150           0 :         return -1;
     151             :     }
     152             : 
     153             :     // TODO: color reduction, similar to dvdsub encoder
     154           0 :     if (h->rects[0]->nb_colors > 4)
     155           0 :         av_log(avctx, AV_LOG_WARNING, "No more than 4 subtitle colors supported (%d found.)\n", h->rects[0]->nb_colors);
     156             : 
     157             :     // TODO: Palette swapping if color zero is not transparent
     158           0 :     if (((uint32_t *)h->rects[0]->data[1])[0] & 0xff000000)
     159           0 :         av_log(avctx, AV_LOG_WARNING, "Color index 0 is not transparent. Transparency will be messed up.\n");
     160             : 
     161           0 :     if (make_tc(startTime, start_tc) || make_tc(endTime, end_tc)) {
     162           0 :         av_log(avctx, AV_LOG_WARNING, "Time code >= 100 hours.\n");
     163           0 :         return -1;
     164             :     }
     165             : 
     166           0 :     snprintf(buf, 28,
     167             :         "[%02d:%02d:%02d.%03d-%02d:%02d:%02d.%03d]",
     168             :         start_tc[3], start_tc[2], start_tc[1], start_tc[0],
     169             :         end_tc[3],   end_tc[2],   end_tc[1],   end_tc[0]);
     170             : 
     171             :     // Width and height must probably be multiples of 2.
     172             :     // 2 pixels required on either side of subtitle.
     173             :     // Possibly due to limitations of hardware renderers.
     174             :     // TODO: check if the bitmap is already padded
     175           0 :     width  = FFALIGN(h->rects[0]->w, 2) + PADDING * 2;
     176           0 :     height = FFALIGN(h->rects[0]->h, 2);
     177             : 
     178           0 :     bytestream_put_le16(&hdr, width);
     179           0 :     bytestream_put_le16(&hdr, height);
     180           0 :     bytestream_put_le16(&hdr, h->rects[0]->x);
     181           0 :     bytestream_put_le16(&hdr, h->rects[0]->y);
     182           0 :     bytestream_put_le16(&hdr, h->rects[0]->x + width -1);
     183           0 :     bytestream_put_le16(&hdr, h->rects[0]->y + height -1);
     184             : 
     185           0 :     rlelenptr = hdr; // Will store length of first field here later.
     186           0 :     hdr+=2;
     187             : 
     188             :     // Palette
     189           0 :     for (i=0; i<4; i++)
     190           0 :         bytestream_put_be24(&hdr, ((uint32_t *)h->rects[0]->data[1])[i]);
     191             : 
     192             :     // Bitmap
     193             :     // RLE buffer. Reserve 2 bytes for possible padding after the last row.
     194           0 :     init_put_bits(&pb, hdr, bufsize - (hdr - buf) - 2);
     195           0 :     if (xsub_encode_rle(&pb, h->rects[0]->data[0],
     196           0 :                         h->rects[0]->linesize[0] * 2,
     197           0 :                         h->rects[0]->w, (h->rects[0]->h + 1) >> 1))
     198           0 :         return -1;
     199           0 :     bytestream_put_le16(&rlelenptr, put_bits_count(&pb) >> 3); // Length of first field
     200             : 
     201           0 :     if (xsub_encode_rle(&pb, h->rects[0]->data[0] + h->rects[0]->linesize[0],
     202           0 :                         h->rects[0]->linesize[0] * 2,
     203           0 :                         h->rects[0]->w, h->rects[0]->h >> 1))
     204           0 :         return -1;
     205             : 
     206             :     // Enforce total height to be a multiple of 2
     207           0 :     if (h->rects[0]->h & 1) {
     208           0 :         put_xsub_rle(&pb, h->rects[0]->w, PADDING_COLOR);
     209           0 :         avpriv_align_put_bits(&pb);
     210             :     }
     211             : 
     212           0 :     flush_put_bits(&pb);
     213             : 
     214           0 :     return hdr - buf + put_bits_count(&pb)/8;
     215             : }
     216             : 
     217           0 : static av_cold int xsub_encoder_init(AVCodecContext *avctx)
     218             : {
     219           0 :     if (!avctx->codec_tag)
     220           0 :         avctx->codec_tag = MKTAG('D','X','S','B');
     221             : 
     222           0 :     avctx->bits_per_coded_sample = 4;
     223             : 
     224           0 :     return 0;
     225             : }
     226             : 
     227             : AVCodec ff_xsub_encoder = {
     228             :     .name       = "xsub",
     229             :     .long_name  = NULL_IF_CONFIG_SMALL("DivX subtitles (XSUB)"),
     230             :     .type       = AVMEDIA_TYPE_SUBTITLE,
     231             :     .id         = AV_CODEC_ID_XSUB,
     232             :     .init       = xsub_encoder_init,
     233             :     .encode_sub = xsub_encode,
     234             : };

Generated by: LCOV version 1.13