Blame src/libbluray/decoders/graphics_processor.c

Packit 5e46da
/*
Packit 5e46da
 * This file is part of libbluray
Packit 5e46da
 * Copyright (C) 2010-2013  Petri Hintukainen <phintuka@users.sourceforge.net>
Packit 5e46da
 *
Packit 5e46da
 * This library is free software; you can redistribute it and/or
Packit 5e46da
 * modify it under the terms of the GNU Lesser General Public
Packit 5e46da
 * License as published by the Free Software Foundation; either
Packit 5e46da
 * version 2.1 of the License, or (at your option) any later version.
Packit 5e46da
 *
Packit 5e46da
 * This library is distributed in the hope that it will be useful,
Packit 5e46da
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 5e46da
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 5e46da
 * Lesser General Public License for more details.
Packit 5e46da
 *
Packit 5e46da
 * You should have received a copy of the GNU Lesser General Public
Packit 5e46da
 * License along with this library. If not, see
Packit 5e46da
 * <http://www.gnu.org/licenses/>.
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
#if HAVE_CONFIG_H
Packit 5e46da
#include "config.h"
Packit 5e46da
#endif
Packit 5e46da
Packit 5e46da
#include "graphics_processor.h"
Packit 5e46da
Packit 5e46da
#include "ig_decode.h"
Packit 5e46da
#include "pg_decode.h"
Packit 5e46da
#include "textst_decode.h"
Packit 5e46da
#include "pes_buffer.h"
Packit 5e46da
#include "m2ts_demux.h"
Packit 5e46da
Packit 5e46da
#include "util/macro.h"
Packit 5e46da
#include "util/logging.h"
Packit 5e46da
#include "util/bits.h"
Packit 5e46da
Packit 5e46da
#include <string.h>
Packit 5e46da
#include <stdlib.h>
Packit 5e46da
#include <inttypes.h>
Packit 5e46da
Packit 5e46da
#define GP_TRACE(...) do {} while (0)
Packit 5e46da
Packit 5e46da
Packit 5e46da
/*
Packit 5e46da
 * segment types
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
typedef enum {
Packit 5e46da
    PGS_PALETTE        = 0x14,
Packit 5e46da
    PGS_OBJECT         = 0x15,
Packit 5e46da
    PGS_PG_COMPOSITION = 0x16,
Packit 5e46da
    PGS_WINDOW         = 0x17,
Packit 5e46da
    PGS_IG_COMPOSITION = 0x18,
Packit 5e46da
    PGS_END_OF_DISPLAY = 0x80,
Packit 5e46da
    /* Text subtitles */
Packit 5e46da
    TGS_DIALOG_STYLE        = 0x81,
Packit 5e46da
    TGS_DIALOG_PRESENTATION = 0x82,
Packit 5e46da
} pgs_segment_type_e;
Packit 5e46da
Packit 5e46da
/*
Packit 5e46da
 * PG_DISPLAY_SET
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
static void _free_dialogs(PG_DISPLAY_SET *s)
Packit 5e46da
{
Packit 5e46da
    unsigned ii;
Packit 5e46da
Packit 5e46da
    textst_free_dialog_style(&s->style);
Packit 5e46da
Packit 5e46da
    for (ii = 0; ii < s->num_dialog; ii++) {
Packit 5e46da
        textst_clean_dialog_presentation(&s->dialog[ii]);
Packit 5e46da
    }
Packit 5e46da
    X_FREE(s->dialog);
Packit 5e46da
Packit 5e46da
    s->num_dialog = 0;
Packit 5e46da
    s->total_dialog = 0;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
void pg_display_set_free(PG_DISPLAY_SET **s)
Packit 5e46da
{
Packit 5e46da
    if (s && *s) {
Packit 5e46da
        unsigned ii;
Packit 5e46da
        for (ii = 0; ii < (*s)->num_object; ii++) {
Packit 5e46da
            pg_clean_object(&(*s)->object[ii]);
Packit 5e46da
        }
Packit 5e46da
        ig_free_interactive(&(*s)->ics);
Packit 5e46da
Packit 5e46da
        X_FREE((*s)->window);
Packit 5e46da
        X_FREE((*s)->object);
Packit 5e46da
        X_FREE((*s)->palette);
Packit 5e46da
Packit 5e46da
        _free_dialogs(*s);
Packit 5e46da
Packit 5e46da
        X_FREE(*s);
Packit 5e46da
    }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
/*
Packit 5e46da
 * segment handling
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
static PES_BUFFER *_find_segment_by_idv(PES_BUFFER *p,
Packit 5e46da
                                        uint8_t seg_type, unsigned idv_pos,
Packit 5e46da
                                        uint8_t *idv, unsigned idv_len)
Packit 5e46da
{
Packit 5e46da
    while (p && (p->buf[0] != seg_type || memcmp(p->buf + idv_pos, idv, idv_len))) {
Packit 5e46da
        p = p->next;
Packit 5e46da
    }
Packit 5e46da
    return p;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void _join_fragments(PES_BUFFER *p1, PES_BUFFER *p2, int data_pos)
Packit 5e46da
{
Packit 5e46da
    unsigned new_len = p1->len + p2->len - data_pos;
Packit 5e46da
Packit 5e46da
    if (p1->size < new_len) {
Packit 5e46da
        uint8_t *tmp;
Packit 5e46da
        p1->size = new_len + 1;
Packit 5e46da
        tmp = realloc(p1->buf, p1->size);
Packit 5e46da
        if (!tmp) {
Packit 5e46da
            BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n");
Packit 5e46da
            p1->size = 0;
Packit 5e46da
            p1->len = 0;
Packit 5e46da
            return;
Packit 5e46da
        }
Packit 5e46da
        p1->buf = tmp;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    memcpy(p1->buf + p1->len, p2->buf + data_pos, p2->len - data_pos);
Packit 5e46da
    p1->len = new_len;
Packit 5e46da
    p2->len = 0;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
/* return 1 if segment is ready for decoding, 0 if more data is needed */
Packit 5e46da
static int _join_segment_fragments(struct pes_buffer_s *p)
Packit 5e46da
{
Packit 5e46da
    uint8_t type;
Packit 5e46da
    unsigned id_pos = 0, id_len = 3, sd_pos = 6, data_pos = 0;
Packit 5e46da
Packit 5e46da
    if (p->len < 3) {
Packit 5e46da
        return 1;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    /* check segment type */
Packit 5e46da
Packit 5e46da
    type = p->buf[0];
Packit 5e46da
    if (type == PGS_OBJECT) {
Packit 5e46da
        id_pos = 3;
Packit 5e46da
        sd_pos = 6;
Packit 5e46da
        data_pos = 7;
Packit 5e46da
    }
Packit 5e46da
    else if (type == PGS_IG_COMPOSITION) {
Packit 5e46da
        id_pos = 8;
Packit 5e46da
        sd_pos = 11;
Packit 5e46da
        data_pos = 12;
Packit 5e46da
    }
Packit 5e46da
    else {
Packit 5e46da
        return 1;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    /* check sequence descriptor - is segment complete ? */
Packit 5e46da
Packit 5e46da
    BD_PG_SEQUENCE_DESCRIPTOR sd;
Packit 5e46da
    BITBUFFER bb;
Packit 5e46da
    bb_init(&bb, p->buf + sd_pos, 3);
Packit 5e46da
    pg_decode_sequence_descriptor(&bb, &sd);
Packit 5e46da
Packit 5e46da
    if (sd.last_in_seq) {
Packit 5e46da
        return 1;
Packit 5e46da
    }
Packit 5e46da
    if (!sd.first_in_seq) {
Packit 5e46da
        return 1;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    /* find next fragment(s) */
Packit 5e46da
Packit 5e46da
    PES_BUFFER *next;
Packit 5e46da
    while (NULL != (next = _find_segment_by_idv(p->next, p->buf[0], id_pos, p->buf + id_pos, id_len))) {
Packit 5e46da
Packit 5e46da
        bb_init(&bb, next->buf + sd_pos, 3);
Packit 5e46da
        pg_decode_sequence_descriptor(&bb, &sd);
Packit 5e46da
Packit 5e46da
        _join_fragments(p, next, data_pos);
Packit 5e46da
Packit 5e46da
        pes_buffer_remove(&p, next);
Packit 5e46da
Packit 5e46da
        if (sd.last_in_seq) {
Packit 5e46da
            /* set first + last in sequence descriptor */
Packit 5e46da
            p->buf[sd_pos] = 0xff;
Packit 5e46da
            return 1;
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    /* do not delay decoding if there are other segments queued (missing fragment ?) */
Packit 5e46da
    return !!p->next;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
/*
Packit 5e46da
 * segment decoding
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
static int _decode_wds(PG_DISPLAY_SET *s, BITBUFFER *bb, PES_BUFFER *p)
Packit 5e46da
{
Packit 5e46da
    BD_PG_WINDOWS w;
Packit 5e46da
    memset(&w, 0, sizeof(w));
Packit 5e46da
Packit 5e46da
    (void)p;
Packit 5e46da
Packit 5e46da
    if (!s->decoding) {
Packit 5e46da
        BD_DEBUG(DBG_DECODE, "skipping orphan window definition segment\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    s->num_window = 0;
Packit 5e46da
Packit 5e46da
    if (pg_decode_windows(bb, &w)) {
Packit 5e46da
        X_FREE(s->window);
Packit 5e46da
        s->window = w.window;
Packit 5e46da
        s->num_window = w.num_windows;
Packit 5e46da
        return 1;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    pg_clean_windows(&w);
Packit 5e46da
Packit 5e46da
    return 0;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int _decode_ods(PG_DISPLAY_SET *s, BITBUFFER *bb, PES_BUFFER *p)
Packit 5e46da
{
Packit 5e46da
    if (!s->decoding) {
Packit 5e46da
        BD_DEBUG(DBG_DECODE, "skipping orphan object definition segment\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    /* search for object to be updated */
Packit 5e46da
Packit 5e46da
    if (s->object) {
Packit 5e46da
        BITBUFFER bb_tmp = *bb;
Packit 5e46da
        uint16_t  id     = bb_read(&bb_tmp, 16);
Packit 5e46da
        unsigned  ii;
Packit 5e46da
Packit 5e46da
        for (ii = 0; ii < s->num_object; ii++) {
Packit 5e46da
            if (s->object[ii].id == id) {
Packit 5e46da
                if (pg_decode_object(bb, &s->object[ii])) {
Packit 5e46da
                    s->object[ii].pts = p->pts;
Packit 5e46da
                    return 1;
Packit 5e46da
                }
Packit 5e46da
                pg_clean_object(&s->object[ii]);
Packit 5e46da
                return 0;
Packit 5e46da
            }
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    /* add and decode new object */
Packit 5e46da
Packit 5e46da
    BD_PG_OBJECT *tmp = realloc(s->object, sizeof(s->object[0]) * (s->num_object + 1));
Packit 5e46da
    if (!tmp) {
Packit 5e46da
        BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
    s->object = tmp;
Packit 5e46da
    memset(&s->object[s->num_object], 0, sizeof(s->object[0]));
Packit 5e46da
Packit 5e46da
    if (pg_decode_object(bb, &s->object[s->num_object])) {
Packit 5e46da
        s->object[s->num_object].pts = p->pts;
Packit 5e46da
        s->num_object++;
Packit 5e46da
        return 1;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    pg_clean_object(&s->object[s->num_object]);
Packit 5e46da
Packit 5e46da
    return 0;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int _decode_pds(PG_DISPLAY_SET *s, BITBUFFER *bb, PES_BUFFER *p)
Packit 5e46da
{
Packit 5e46da
    if (!s->decoding) {
Packit 5e46da
        BD_DEBUG(DBG_DECODE, "skipping orphan palette definition segment\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    /* search for palette to be updated */
Packit 5e46da
Packit 5e46da
    if (s->palette) {
Packit 5e46da
        BITBUFFER bb_tmp = *bb;
Packit 5e46da
        uint8_t   id     = bb_read(&bb_tmp, 8);
Packit 5e46da
        unsigned  ii;
Packit 5e46da
Packit 5e46da
        for (ii = 0; ii < s->num_palette; ii++) {
Packit 5e46da
            if (s->palette[ii].id == id) {
Packit 5e46da
                int rr;
Packit 5e46da
                if ( (s->ics && s->ics->composition_descriptor.state == 0) ||
Packit 5e46da
                     (s->pcs && s->pcs->composition_descriptor.state == 0)) {
Packit 5e46da
                    /* 8.8.3.1.1 */
Packit 5e46da
                    rr = pg_decode_palette_update(bb, &s->palette[ii]);
Packit 5e46da
                } else {
Packit 5e46da
                    rr = pg_decode_palette(bb, &s->palette[ii]);
Packit 5e46da
                }
Packit 5e46da
                if (rr) {
Packit 5e46da
                    s->palette[ii].pts = p->pts;
Packit 5e46da
                    return 1;
Packit 5e46da
                }
Packit 5e46da
                return 0;
Packit 5e46da
            }
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    /* add and decode new palette */
Packit 5e46da
Packit 5e46da
    BD_PG_PALETTE *tmp = realloc(s->palette, sizeof(s->palette[0]) * (s->num_palette + 1));
Packit 5e46da
    if (!tmp) {
Packit 5e46da
        BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
    s->palette = tmp;
Packit 5e46da
    memset(&s->palette[s->num_palette], 0, sizeof(s->palette[0]));
Packit 5e46da
Packit 5e46da
    if (pg_decode_palette(bb, &s->palette[s->num_palette])) {
Packit 5e46da
        s->palette[s->num_palette].pts = p->pts;
Packit 5e46da
        s->num_palette++;
Packit 5e46da
        return 1;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    return 0;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void _check_epoch_start(PG_DISPLAY_SET *s)
Packit 5e46da
{
Packit 5e46da
    if ((s->pcs && s->pcs->composition_descriptor.state == 2) ||
Packit 5e46da
        (s->ics && s->ics->composition_descriptor.state == 2)) {
Packit 5e46da
        /* epoch start, drop all cached data */
Packit 5e46da
Packit 5e46da
        unsigned ii;
Packit 5e46da
        for (ii = 0; ii < s->num_object; ii++) {
Packit 5e46da
            pg_clean_object(&s->object[ii]);
Packit 5e46da
        }
Packit 5e46da
Packit 5e46da
        s->num_palette = 0;
Packit 5e46da
        s->num_window  = 0;
Packit 5e46da
        s->num_object  = 0;
Packit 5e46da
Packit 5e46da
        s->epoch_start = 1;
Packit 5e46da
Packit 5e46da
    } else {
Packit 5e46da
        s->epoch_start = 0;
Packit 5e46da
    }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int _decode_pcs(PG_DISPLAY_SET *s, BITBUFFER *bb, PES_BUFFER *p)
Packit 5e46da
{
Packit 5e46da
    if (s->complete) {
Packit 5e46da
        BD_DEBUG(DBG_DECODE | DBG_CRIT, "ERROR: updating complete (non-consumed) PG composition\n");
Packit 5e46da
        s->complete = 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    pg_free_composition(&s->pcs);
Packit 5e46da
    s->pcs = calloc(1, sizeof(*s->pcs));
Packit 5e46da
    if (!s->pcs) {
Packit 5e46da
        BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    if (!pg_decode_composition(bb, s->pcs)) {
Packit 5e46da
        pg_free_composition(&s->pcs);
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    s->pcs->pts  = p->pts;
Packit 5e46da
    s->valid_pts = p->pts;
Packit 5e46da
Packit 5e46da
    _check_epoch_start(s);
Packit 5e46da
Packit 5e46da
    s->decoding = 1;
Packit 5e46da
Packit 5e46da
    return 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int _decode_ics(PG_DISPLAY_SET *s, BITBUFFER *bb, PES_BUFFER *p)
Packit 5e46da
{
Packit 5e46da
    if (s->complete) {
Packit 5e46da
        BD_DEBUG(DBG_DECODE | DBG_CRIT, "ERROR: updating complete (non-consumed) IG composition\n");
Packit 5e46da
        s->complete = 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    ig_free_interactive(&s->ics);
Packit 5e46da
    s->ics = calloc(1, sizeof(*s->ics));
Packit 5e46da
    if (!s->ics) {
Packit 5e46da
        BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    if (!ig_decode_interactive(bb, s->ics)) {
Packit 5e46da
        ig_free_interactive(&s->ics);
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    s->ics->pts  = p->pts;
Packit 5e46da
    s->valid_pts = p->pts;
Packit 5e46da
Packit 5e46da
    _check_epoch_start(s);
Packit 5e46da
Packit 5e46da
    s->decoding = 1;
Packit 5e46da
Packit 5e46da
    return 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int _decode_dialog_style(PG_DISPLAY_SET *s, BITBUFFER *bb)
Packit 5e46da
{
Packit 5e46da
    _free_dialogs(s);
Packit 5e46da
Packit 5e46da
    s->complete = 0;
Packit 5e46da
Packit 5e46da
    s->style = calloc(1, sizeof(*s->style));
Packit 5e46da
    if (!s->style) {
Packit 5e46da
        BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    if (!textst_decode_dialog_style(bb, s->style)) {
Packit 5e46da
        textst_free_dialog_style(&s->style);
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    if (bb->p != bb->p_end - 2 || bb->i_left != 8) {
Packit 5e46da
        BD_DEBUG(DBG_DECODE | DBG_CRIT, "_decode_dialog_style() failed: bytes in buffer %d\n", (int)(bb->p_end - bb->p));
Packit 5e46da
        textst_free_dialog_style(&s->style);
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    s->total_dialog = bb_read(bb, 16);
Packit 5e46da
    if (s->total_dialog < 1) {
Packit 5e46da
        BD_DEBUG(DBG_DECODE | DBG_CRIT, "_decode_dialog_style(): no dialog segments\n");
Packit 5e46da
        textst_free_dialog_style(&s->style);
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    s->dialog = calloc(s->total_dialog, sizeof(*s->dialog));
Packit 5e46da
    if (!s->dialog) {
Packit 5e46da
        BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n");
Packit 5e46da
        s->total_dialog = 0;
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    BD_DEBUG(DBG_DECODE, "_decode_dialog_style(): %d dialogs in stream\n", s->total_dialog);
Packit 5e46da
    return 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int _decode_dialog_presentation(PG_DISPLAY_SET *s, BITBUFFER *bb)
Packit 5e46da
{
Packit 5e46da
    if (!s->style || s->total_dialog < 1) {
Packit 5e46da
        BD_DEBUG(DBG_DECODE, "_decode_dialog_presentation() failed: style segment not decoded\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
    if (s->num_dialog >= s->total_dialog) {
Packit 5e46da
        BD_DEBUG(DBG_DECODE | DBG_CRIT, "_decode_dialog_presentation(): unexpected dialog segment\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    if (!textst_decode_dialog_presentation(bb, &s->dialog[s->num_dialog])) {
Packit 5e46da
        textst_clean_dialog_presentation(&s->dialog[s->num_dialog]);
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    s->num_dialog++;
Packit 5e46da
Packit 5e46da
    if (s->num_dialog == s->total_dialog) {
Packit 5e46da
        s->complete = 1;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    return 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int _decode_segment(PG_DISPLAY_SET *s, PES_BUFFER *p)
Packit 5e46da
{
Packit 5e46da
    BITBUFFER bb;
Packit 5e46da
    bb_init(&bb, p->buf, p->len);
Packit 5e46da
Packit 5e46da
    uint8_t type   =    bb_read(&bb, 8);
Packit 5e46da
    /*uint16_t len = */ bb_read(&bb, 16);
Packit 5e46da
    switch (type) {
Packit 5e46da
        case PGS_OBJECT:
Packit 5e46da
            return _decode_ods(s, &bb, p);
Packit 5e46da
Packit 5e46da
        case PGS_PALETTE:
Packit 5e46da
            return _decode_pds(s, &bb, p);
Packit 5e46da
Packit 5e46da
        case PGS_WINDOW:
Packit 5e46da
            return _decode_wds(s, &bb, p);
Packit 5e46da
Packit 5e46da
        case PGS_PG_COMPOSITION:
Packit 5e46da
            return _decode_pcs(s, &bb, p);
Packit 5e46da
Packit 5e46da
        case PGS_IG_COMPOSITION:
Packit 5e46da
            return _decode_ics(s, &bb, p);
Packit 5e46da
Packit 5e46da
        case PGS_END_OF_DISPLAY:
Packit 5e46da
            if (!s->decoding) {
Packit 5e46da
                /* avoid duplicate initialization / presenataton */
Packit 5e46da
                BD_DEBUG(DBG_DECODE, "skipping orphan end of display segment\n");
Packit 5e46da
                return 0;
Packit 5e46da
            }
Packit 5e46da
            s->complete = 1;
Packit 5e46da
            s->decoding = 0;
Packit 5e46da
            return 1;
Packit 5e46da
Packit 5e46da
        case TGS_DIALOG_STYLE:
Packit 5e46da
          return _decode_dialog_style(s, &bb);
Packit 5e46da
Packit 5e46da
        case TGS_DIALOG_PRESENTATION:
Packit 5e46da
          return _decode_dialog_presentation(s, &bb);
Packit 5e46da
Packit 5e46da
        default:
Packit 5e46da
            BD_DEBUG(DBG_DECODE | DBG_CRIT, "unknown segment type 0x%x\n", type);
Packit 5e46da
            break;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    return 0;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
/*
Packit 5e46da
 * mpeg-pes interface
Packit 5e46da
 */
Packit 5e46da
#define MAX_STC_DTS_DIFF (INT64_C(90000 * 30)) /* 30 seconds */
Packit 5e46da
static int graphics_processor_decode_pes(PG_DISPLAY_SET **s, PES_BUFFER **p, int64_t stc)
Packit 5e46da
{
Packit 5e46da
    if (!s) {
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    if (*s == NULL) {
Packit 5e46da
        *s = calloc(1, sizeof(PG_DISPLAY_SET));
Packit 5e46da
        if (!*s) {
Packit 5e46da
            BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n");
Packit 5e46da
            return 0;
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    while (*p) {
Packit 5e46da
Packit 5e46da
        /* time to decode next segment ? */
Packit 5e46da
        if (stc >= 0 && (*p)->dts > stc) {
Packit 5e46da
Packit 5e46da
            /* filter out values that seem to be incorrect (if stc is not updated) */
Packit 5e46da
            int64_t diff = (*p)->dts - stc;
Packit 5e46da
            if (diff < MAX_STC_DTS_DIFF) {
Packit 5e46da
                GP_TRACE("Segment dts > stc (%"PRId64" > %"PRId64" ; diff %"PRId64")\n",
Packit 5e46da
                         (*p)->dts, stc, diff);
Packit 5e46da
                return 0;
Packit 5e46da
            }
Packit 5e46da
        }
Packit 5e46da
Packit 5e46da
        /* all fragments present ? */
Packit 5e46da
        if (!_join_segment_fragments(*p)) {
Packit 5e46da
            GP_TRACE("splitted segment not complete, waiting for next fragment\n");
Packit 5e46da
            return 0;
Packit 5e46da
        }
Packit 5e46da
Packit 5e46da
        if ((*p)->len <= 2) {
Packit 5e46da
            BD_DEBUG(DBG_DECODE, "segment too short, skipping (%d bytes)\n", (*p)->len);
Packit 5e46da
            pes_buffer_next(p);
Packit 5e46da
            continue;
Packit 5e46da
        }
Packit 5e46da
Packit 5e46da
        /* decode segment */
Packit 5e46da
Packit 5e46da
        GP_TRACE("Decoding segment, dts %010"PRId64" pts %010"PRId64" len %d\n",
Packit 5e46da
                 (*p)->dts, (*p)->pts, (*p)->len);
Packit 5e46da
Packit 5e46da
        _decode_segment(*s, *p);
Packit 5e46da
Packit 5e46da
        pes_buffer_next(p);
Packit 5e46da
Packit 5e46da
        if ((*s)->complete) {
Packit 5e46da
            return 1;
Packit 5e46da
        }
Packit 5e46da
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    return 0;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
/*
Packit 5e46da
 * mpeg-ts interface
Packit 5e46da
 */
Packit 5e46da
Packit 5e46da
struct graphics_processor_s {
Packit 5e46da
    uint16_t    pid;
Packit 5e46da
    M2TS_DEMUX  *demux;
Packit 5e46da
    PES_BUFFER  *queue;
Packit 5e46da
};
Packit 5e46da
Packit 5e46da
GRAPHICS_PROCESSOR *graphics_processor_init(void)
Packit 5e46da
{
Packit 5e46da
    GRAPHICS_PROCESSOR *p = calloc(1, sizeof(*p));
Packit 5e46da
Packit 5e46da
    return p;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
void graphics_processor_free(GRAPHICS_PROCESSOR **p)
Packit 5e46da
{
Packit 5e46da
    if (p && *p) {
Packit 5e46da
        m2ts_demux_free(&(*p)->demux);
Packit 5e46da
        pes_buffer_free(&(*p)->queue);
Packit 5e46da
Packit 5e46da
        X_FREE(*p);
Packit 5e46da
    }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
int graphics_processor_decode_ts(GRAPHICS_PROCESSOR *p,
Packit 5e46da
                                 PG_DISPLAY_SET **s,
Packit 5e46da
                                 uint16_t pid, uint8_t *unit, unsigned num_units,
Packit 5e46da
                                 int64_t stc)
Packit 5e46da
{
Packit 5e46da
    unsigned ii;
Packit 5e46da
    int result = 0;
Packit 5e46da
Packit 5e46da
    if (pid != p->pid) {
Packit 5e46da
        m2ts_demux_free(&p->demux);
Packit 5e46da
        pes_buffer_free(&p->queue);
Packit 5e46da
    }
Packit 5e46da
    if (!p->demux) {
Packit 5e46da
        p->demux = m2ts_demux_init(pid);
Packit 5e46da
        if (!p->demux) {
Packit 5e46da
            return 0;
Packit 5e46da
        }
Packit 5e46da
        p->pid   = pid;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    for (ii = 0; ii < num_units; ii++) {
Packit 5e46da
        pes_buffer_append(&p->queue, m2ts_demux(p->demux, unit));
Packit 5e46da
        unit += 6144;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    if (p->queue) {
Packit 5e46da
        result = graphics_processor_decode_pes(s, &p->queue, stc);
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    return result;
Packit 5e46da
}