首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在文件中从AVSubtitle转储字幕

在文件中从AVSubtitle转储字幕
EN

Stack Overflow用户
提问于 2019-01-10 09:09:57
回答 2查看 825关注 0票数 0

在ffmpeg软件中,AVPicture采用数据指针存储图像数据,linesizes.It表示所有字幕都以图片形式存储在FFMPEG中。现在我有了DVB字幕,我想将存储在AVPicture中的字幕图片转储到缓冲区中。我知道这些图片字幕可以用于转储,fopen和sprintf。但不知道如何转储字幕,我不得不转储.ppm文件格式的字幕。

有人能帮我从AVSubtitle的缓冲区中转储字幕图片吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-01-11 09:22:05

这个过程看起来很复杂,但实际上非常简单。

AVSubtitle是通用格式,支持文本和位图模式。Dvbsub格式仅afaik位图和位图格式可以不同,如16色或256色模式,如CLUT_DEPTH

我相信(在当前的ffmpeg)存储在AVSubtitleRect结构中的位图,它是AVSubtitle的成员。

我假设您有一个有效的AVSubtitle包,如果我理解正确,您可以这样做,并且它应该可以工作:

1)检查pkt->rect[0]->type。这里的pkt是一个有效的AVSubtitle包。它必须是SUBTITLE_BITMAP的类型。

2)如果是这样的话,可以从pkt->rects[0]->wpkt->rects[0]->h中读取带有高度的位图。

3)位图数据本身为pkt->rects[0]->data[0]

4) CLUT_DEPTH可以从pkt->rects[0]->nb_colors中读取。

5)和CLUT本身(颜色表)将在pkt->rects[0]->data[1]中。

使用这些数据,您可以构造一个可在windows或linux桌面上查看的有效.bmp文件,但我将此部分留给了您。

PPM信息

首先检查有关PPM格式的信息:

info.html

据我所知,PPM格式使用RGB值(24位/3字节)。在我看来,您所要做的就是根据从上面的AVSubtitle数据包中获取的数据构造一个报头。并为dvbsub的索引色缓冲区编写一个转换函数到RGB。我很肯定有些地方已经准备好使用密码了,但我还是会解释的。

在画框数据中,Dvbsub使用的是线性数据,每个像素都是1字节(甚至在16色模式下)。这个字节值实际上是对应于RGB (?)存储在颜色查找表(CLUT)中的值,在16种颜色模式下,每个4字节有16个索引,前3个是R、G、B值,第4个是alpha值(透明度值,如果PPM不支持这一点,请忽略它)。

我不确定解码后的字幕是否仍有编码的YUV值。我记得它应该是普通的RGBA格式。

ffmpeg上的encode_dvb_subtitles函数显示了这种编码是如何完成的。如果你需要的话。

https://github.com/FFmpeg/FFmpeg/blob/a0ac49e38ee1d1011c394d7be67d0f08b2281526/libavcodec/dvbsub.c

希望这能有所帮助。

票数 1
EN

Stack Overflow用户

发布于 2022-08-19 12:01:03

由于这是我在寻找如何创建AVSubtitle缩略图的答案时结束的地方,下面是我在测试应用程序中使用的内容。该代码是为可读性而优化的。我得到了一些this question的帮助,它有一些示例代码。

使用avcodec_decode_subtitle2(),我得到了一个AVSubtitle结构。这包含许多矩形。首先,我在矩形上迭代,找出x+w和y+h的最大值,以确定目标帧的宽度和高度。

data1中的颜色表是RGBA,因此我以AV_PIX_FMT_RGBA格式分配了一个名为frame的AVFrame,并将像素洗牌到它:

代码语言:javascript
复制
struct [[gnu::packed]] rgbaPixel {
    uint8_t r;
    uint8_t g;
    uint8_t b;
    uint8_t a;
};

// Copy the pixel buffers
for (unsigned int i = 0; i < sub.num_rects; ++ i) {
    AVSubtitleRect* rect = sub.rects[i];
    for (int y = 0; y < rect->h; ++ y) {
        int dest_y = y + rect->y;

        // data[0] holds index data
        uint8_t *in_linedata = rect->data[0] + y * rect->linesize[0];

        // In AVFrame, data[0] holds the pixel buffer directly
        uint8_t *out_linedata = frame->data[0] + dest_y * frame->linesize[0];
        rgbaPixel *out_pixels = reinterpret_cast<rgbaPixel*>(out_linedata);

        for (int x = 0; x < rect->w; ++ x) {
            // data[1] contains the color map
            // compare libavcodec/dvbsubenc.c
            uint8_t colidx = in_linedata[x];
            uint32_t color = reinterpret_cast<uint32_t*>(rect->data[1])[colidx];

            // Now store the pixel in the target buffer
            out_pixels[x + rect->x] = rgbaPixel{
                .r = static_cast<uint8_t>((color >> 16) & 0xff),
                .g = static_cast<uint8_t>((color >>  8) & 0xff),
                .b = static_cast<uint8_t>((color >>  0) & 0xff),
                .a = static_cast<uint8_t>((color >> 24) & 0xff),
            };
        }
    }
}    

我确实成功地将这个AVFrame通过图像解码器输出为位图图像,而且它看起来还不错。我确实得到了α通道所在的绿色区域,但这可能是我使用的JPEG编码器中设置的一个工件。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54125207

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档