⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dvdsubenc.c

📁 ffmpeg源码分析
💻 C
字号:
/* * DVD subtitle encoding for ffmpeg * Copyright (c) 2005 Wolfram Gloger. * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */#include "avcodec.h"#undef NDEBUG#include <assert.h>typedef struct DVDSubtitleContext {} DVDSubtitleContext;// ncnt is the nibble counter#define PUTNIBBLE(val)\do {\    if (ncnt++ & 1)\        *q++ = bitbuf | ((val) & 0x0f);\    else\        bitbuf = (val) << 4;\} while(0)static void dvd_encode_rle(uint8_t **pq,                           const uint8_t *bitmap, int linesize,                           int w, int h,                           const int cmap[256]){    uint8_t *q;    unsigned int bitbuf = 0;    int ncnt;    int x, y, len, color;    q = *pq;    for (y = 0; y < h; ++y) {        ncnt = 0;        for(x = 0; x < w; x += len) {            color = bitmap[x];            for (len=1; x+len < w; ++len)                if (bitmap[x+len] != color)                    break;            color = cmap[color];            assert(color < 4);            if (len < 0x04) {                PUTNIBBLE((len << 2)|color);            } else if (len < 0x10) {                PUTNIBBLE(len >> 2);                PUTNIBBLE((len << 2)|color);            } else if (len < 0x40) {                PUTNIBBLE(0);                PUTNIBBLE(len >> 2);                PUTNIBBLE((len << 2)|color);            } else if (x+len == w) {                PUTNIBBLE(0);                PUTNIBBLE(0);                PUTNIBBLE(0);                PUTNIBBLE(color);            } else {                if (len > 0xff)                    len = 0xff;                PUTNIBBLE(0);                PUTNIBBLE(len >> 6);                PUTNIBBLE(len >> 2);                PUTNIBBLE((len << 2)|color);            }        }        /* end of line */        if (ncnt & 1)            PUTNIBBLE(0);        bitmap += linesize;    }    *pq = q;}static inline void putbe16(uint8_t **pq, uint16_t v){    uint8_t *q = *pq;    *q++ = v >> 8;    *q++ = v;    *pq = q;}static int encode_dvd_subtitles(uint8_t *outbuf, int outbuf_size,                                const AVSubtitle *h){    uint8_t *q, *qq;    int object_id;    int offset1[20], offset2[20];    int i, imax, color, alpha, rects = h->num_rects;    unsigned long hmax;    unsigned long hist[256];    int           cmap[256];    if (rects == 0 || h->rects == NULL)        return -1;    if (rects > 20)        rects = 20;    // analyze bitmaps, compress to 4 colors    for (i=0; i<256; ++i) {        hist[i] = 0;        cmap[i] = 0;    }    for (object_id = 0; object_id < rects; object_id++)        for (i=0; i<h->rects[object_id].w*h->rects[object_id].h; ++i) {            color = h->rects[object_id].bitmap[i];            // only count non-transparent pixels            alpha = h->rects[object_id].rgba_palette[color] >> 24;            hist[color] += alpha;        }    for (color=3;; --color) {        hmax = 0;        imax = 0;        for (i=0; i<256; ++i)            if (hist[i] > hmax) {                imax = i;                hmax = hist[i];            }        if (hmax == 0)            break;        if (color == 0)            color = 3;        av_log(NULL, AV_LOG_DEBUG, "dvd_subtitle hist[%d]=%ld -> col %d\n",               imax, hist[imax], color);        cmap[imax] = color;        hist[imax] = 0;    }    // encode data block    q = outbuf + 4;    for (object_id = 0; object_id < rects; object_id++) {        offset1[object_id] = q - outbuf;        // worst case memory requirement: 1 nibble per pixel..        if ((q - outbuf) + h->rects[object_id].w*h->rects[object_id].h/2            + 17*rects + 21 > outbuf_size) {            av_log(NULL, AV_LOG_ERROR, "dvd_subtitle too big\n");            return -1;        }        dvd_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,                       cmap);        offset2[object_id] = q - outbuf;        dvd_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,                       cmap);    }    // set data packet size    qq = outbuf + 2;    putbe16(&qq, q - outbuf);    // send start display command    putbe16(&q, (h->start_display_time*90) >> 10);    putbe16(&q, (q - outbuf) /*- 2 */ + 8 + 12*rects + 2);    *q++ = 0x03; // palette - 4 nibbles    *q++ = 0x03; *q++ = 0x7f;    *q++ = 0x04; // alpha - 4 nibbles    *q++ = 0xf0; *q++ = 0x00;    //*q++ = 0x0f; *q++ = 0xff;    // XXX not sure if more than one rect can really be encoded..    // 12 bytes per rect    for (object_id = 0; object_id < rects; object_id++) {        int x2 = h->rects[object_id].x + h->rects[object_id].w - 1;        int y2 = h->rects[object_id].y + h->rects[object_id].h - 1;        *q++ = 0x05;        // x1 x2 -> 6 nibbles        *q++ = h->rects[object_id].x >> 4;        *q++ = (h->rects[object_id].x << 4) | ((x2 >> 8) & 0xf);        *q++ = x2;        // y1 y2 -> 6 nibbles        *q++ = h->rects[object_id].y >> 4;        *q++ = (h->rects[object_id].y << 4) | ((y2 >> 8) & 0xf);        *q++ = y2;        *q++ = 0x06;        // offset1, offset2        putbe16(&q, offset1[object_id]);        putbe16(&q, offset2[object_id]);    }    *q++ = 0x01; // start command    *q++ = 0xff; // terminating command    // send stop display command last    putbe16(&q, (h->end_display_time*90) >> 10);    putbe16(&q, (q - outbuf) - 2 /*+ 4*/);    *q++ = 0x02; // set end    *q++ = 0xff; // terminating command    qq = outbuf;    putbe16(&qq, q - outbuf);    av_log(NULL, AV_LOG_DEBUG, "subtitle_packet size=%td\n", q - outbuf);    return q - outbuf;}static int dvdsub_init_encoder(AVCodecContext *avctx){    return 0;}static int dvdsub_close_encoder(AVCodecContext *avctx){    return 0;}static int dvdsub_encode(AVCodecContext *avctx,                         unsigned char *buf, int buf_size, void *data){    //DVDSubtitleContext *s = avctx->priv_data;    AVSubtitle *sub = data;    int ret;    ret = encode_dvd_subtitles(buf, buf_size, sub);    return ret;}AVCodec dvdsub_encoder = {    "dvdsub",    CODEC_TYPE_SUBTITLE,    CODEC_ID_DVD_SUBTITLE,    sizeof(DVDSubtitleContext),    dvdsub_init_encoder,    dvdsub_encode,    dvdsub_close_encoder,};/* Local Variables: *//* c-basic-offset:4 *//* End: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -