summaryrefslogtreecommitdiff
path: root/src/internal/subtitle/renderers/kitsubimage.c
blob: 2edafc9522bdfb197318ee57ed9ad2717d2dcbed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include <assert.h>
#include <stdlib.h>

#include <SDL2/SDL_surface.h>

#include "kitchensink/kiterror.h"
#include "kitchensink/internal/utils/kitlog.h"
#include "kitchensink/internal/subtitle/kitatlas.h"
#include "kitchensink/internal/subtitle/kitsubtitlepacket.h"
#include "kitchensink/internal/subtitle/renderers/kitsubimage.h"

static void ren_render_image_cb(Kit_SubtitleRenderer *ren, void *sub_src, double start_pts, double end_pts) {
    assert(ren != NULL);
    assert(sub_src != NULL);

    AVSubtitle *sub = sub_src;
    SDL_Surface *dst = NULL, *src = NULL;

    // If this subtitle has no rects, we still need to clear screen from old subs
    if(sub->num_rects == 0) {
        Kit_WriteDecoderOutput(
            ren->dec, Kit_CreateSubtitlePacket(true, start_pts, end_pts, 0, 0, NULL));
        return;
    }

    // Convert subtitle images from paletted to RGBA8888
    for(int n = 0; n < sub->num_rects; n++) {
        AVSubtitleRect *r = sub->rects[n];
        if(r->type != SUBTITLE_BITMAP)
            continue;

        src = SDL_CreateRGBSurfaceWithFormatFrom(
            r->data[0], r->w, r->h, 8, r->linesize[0], SDL_PIXELFORMAT_INDEX8);
        SDL_SetPaletteColors(src->format->palette, (SDL_Color*)r->data[1], 0, 256);
        dst = SDL_CreateRGBSurfaceWithFormat(
            0, r->w, r->h, 32, SDL_PIXELFORMAT_RGBA32);
        
        // Blit source to target and free source surface.
        SDL_BlitSurface(src, NULL, dst, NULL);
        
        // Create a new packet and write it to output buffer
        Kit_WriteDecoderOutput(
            ren->dec, Kit_CreateSubtitlePacket(false, start_pts, end_pts, r->x, r->y, dst));

        // Free surfaces
        SDL_FreeSurface(src);
        SDL_FreeSurface(dst);
    }
}

static int ren_get_data_cb(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, double current_pts) {
    // Read any new packets to atlas
    Kit_SubtitlePacket *packet = NULL;

    // Clean dead packets
    while((packet = Kit_PeekDecoderOutput(ren->dec)) != NULL) {
        if(packet->pts_end < current_pts) {
            Kit_AdvanceDecoderOutput(ren->dec);
            Kit_FreeSubtitlePacket(packet);
            continue;
        }
        if(packet->pts_start < current_pts) {
            if(packet->clear) {
                Kit_ClearAtlasContent(atlas);
            }
            if(packet->surface != NULL) {
                SDL_Rect target;
                target.x = packet->x;
                target.y = packet->y;
                target.w = packet->surface->w;
                target.h = packet->surface->h;
                Kit_AddAtlasItem(atlas, packet->surface, &target);
            }
            Kit_AdvanceDecoderOutput(ren->dec);
            Kit_FreeSubtitlePacket(packet);
            ren->dec->clock_pos = current_pts;
            continue;
        }
        break;
    }

    return 0;
}

Kit_SubtitleRenderer* Kit_CreateImageSubtitleRenderer(Kit_Decoder *dec, int w, int h) {
    assert(dec != NULL);
    assert(w >= 0);
    assert(h >= 0);

    // Allocate a new renderer
    Kit_SubtitleRenderer *ren = Kit_CreateSubtitleRenderer(dec);
    if(ren == NULL) {
        return NULL;
    }

    // Only renderer required, no other data.
    ren->ren_render = ren_render_image_cb;
    ren->ren_get_data = ren_get_data_cb;
    ren->ren_close = NULL;
    ren->userdata = NULL;
    return ren;
}