Blame src/libbluray/bdnav/clpi_parse.c

Packit 5e46da
/*
Packit 5e46da
 * This file is part of libbluray
Packit 5e46da
 * Copyright (C) 2009-2010  John Stebbins
Packit 5e46da
 * Copyright (C) 2012-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 "clpi_parse.h"
Packit 5e46da
Packit 5e46da
#include "extdata_parse.h"
Packit 5e46da
#include "bdmv_parse.h"
Packit 5e46da
Packit 5e46da
#include "disc/disc.h"
Packit 5e46da
Packit 5e46da
#include "file/file.h"
Packit 5e46da
#include "util/bits.h"
Packit 5e46da
#include "util/macro.h"
Packit 5e46da
#include "util/logging.h"
Packit 5e46da
Packit 5e46da
#include <stdlib.h>
Packit 5e46da
#include <string.h>
Packit 5e46da
Packit 5e46da
#define CLPI_SIG1  ('H' << 24 | 'D' << 16 | 'M' << 8 | 'V')
Packit 5e46da
Packit 5e46da
static int
Packit 5e46da
_parse_stream_attr(BITSTREAM *bits, CLPI_PROG_STREAM *ss)
Packit 5e46da
{
Packit 5e46da
    int64_t pos;
Packit 5e46da
    int len;
Packit 5e46da
Packit 5e46da
    if (!bs_is_align(bits, 0x07)) {
Packit 5e46da
        BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_stream_attr(): Stream alignment error\n");
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    len = bs_read(bits, 8);
Packit 5e46da
    pos = bs_pos(bits) >> 3;
Packit 5e46da
Packit 5e46da
    ss->lang[0] = '\0';
Packit 5e46da
    ss->coding_type = bs_read(bits, 8);
Packit 5e46da
    switch (ss->coding_type) {
Packit 5e46da
        case 0x01:
Packit 5e46da
        case 0x02:
Packit 5e46da
        case 0xea:
Packit 5e46da
        case 0x1b:
Packit 5e46da
        case 0x20:
Packit 5e46da
        case 0x24:
Packit 5e46da
            ss->format = bs_read(bits, 4);
Packit 5e46da
            ss->rate   = bs_read(bits, 4);
Packit 5e46da
            ss->aspect = bs_read(bits, 4);
Packit 5e46da
            bs_skip(bits, 2);
Packit 5e46da
            ss->oc_flag = bs_read(bits, 1);
Packit 5e46da
            bs_skip(bits, 1);
Packit 5e46da
            break;
Packit 5e46da
Packit 5e46da
        case 0x03:
Packit 5e46da
        case 0x04:
Packit 5e46da
        case 0x80:
Packit 5e46da
        case 0x81:
Packit 5e46da
        case 0x82:
Packit 5e46da
        case 0x83:
Packit 5e46da
        case 0x84:
Packit 5e46da
        case 0x85:
Packit 5e46da
        case 0x86:
Packit 5e46da
        case 0xa1:
Packit 5e46da
        case 0xa2:
Packit 5e46da
            ss->format = bs_read(bits, 4);
Packit 5e46da
            ss->rate   = bs_read(bits, 4);
Packit 5e46da
            bs_read_string(bits, ss->lang, 3);
Packit 5e46da
            break;
Packit 5e46da
Packit 5e46da
        case 0x90:
Packit 5e46da
        case 0x91:
Packit 5e46da
        case 0xa0:
Packit 5e46da
            bs_read_string(bits, ss->lang, 3);
Packit 5e46da
            break;
Packit 5e46da
Packit 5e46da
        case 0x92:
Packit 5e46da
            ss->char_code = bs_read(bits, 8);
Packit 5e46da
            bs_read_string(bits, ss->lang, 3);
Packit 5e46da
            break;
Packit 5e46da
Packit 5e46da
        default:
Packit 5e46da
            BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_stream_attr(): unrecognized coding type %02x\n", ss->coding_type);
Packit 5e46da
            break;
Packit 5e46da
    };
Packit 5e46da
    ss->lang[3] = '\0';
Packit 5e46da
Packit 5e46da
    // Skip over any padding
Packit 5e46da
    if (bs_seek_byte(bits, pos + len) < 0) {
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
    return 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int
Packit 5e46da
_parse_header(BITSTREAM *bits, CLPI_CL *cl)
Packit 5e46da
{
Packit 5e46da
    cl->type_indicator = CLPI_SIG1;
Packit 5e46da
    if (!bdmv_parse_header(bits, cl->type_indicator, &cl->type_indicator2)) {
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    if (bs_avail(bits) < 5 * 32) {
Packit 5e46da
        BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_header: unexpected end of file\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    cl->sequence_info_start_addr = bs_read(bits, 32);
Packit 5e46da
    cl->program_info_start_addr = bs_read(bits, 32);
Packit 5e46da
    cl->cpi_start_addr = bs_read(bits, 32);
Packit 5e46da
    cl->clip_mark_start_addr = bs_read(bits, 32);
Packit 5e46da
    cl->ext_data_start_addr = bs_read(bits, 32);
Packit 5e46da
    return 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int
Packit 5e46da
_parse_clipinfo(BITSTREAM *bits, CLPI_CL *cl)
Packit 5e46da
{
Packit 5e46da
    int64_t pos;
Packit 5e46da
    int len;
Packit 5e46da
    int ii;
Packit 5e46da
Packit 5e46da
    if (bs_seek_byte(bits, 40) < 0) {
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    // ClipInfo len
Packit 5e46da
    bs_skip(bits, 32);
Packit 5e46da
    // reserved
Packit 5e46da
    bs_skip(bits, 16);
Packit 5e46da
    cl->clip.clip_stream_type = bs_read(bits, 8);
Packit 5e46da
    cl->clip.application_type = bs_read(bits, 8);
Packit 5e46da
    // skip reserved 31 bits
Packit 5e46da
    bs_skip(bits, 31);
Packit 5e46da
    cl->clip.is_atc_delta       = bs_read(bits, 1);
Packit 5e46da
    cl->clip.ts_recording_rate  = bs_read(bits, 32);
Packit 5e46da
    cl->clip.num_source_packets = bs_read(bits, 32);
Packit 5e46da
Packit 5e46da
    // Skip reserved 128 bytes
Packit 5e46da
    bs_skip(bits, 128 * 8);
Packit 5e46da
Packit 5e46da
    // ts type info block
Packit 5e46da
    len = bs_read(bits, 16);
Packit 5e46da
    pos = bs_pos(bits) >> 3;
Packit 5e46da
    if (len) {
Packit 5e46da
        cl->clip.ts_type_info.validity = bs_read(bits, 8);
Packit 5e46da
        bs_read_string(bits, cl->clip.ts_type_info.format_id, 4);
Packit 5e46da
        // Seek past the stuff we don't know anything about
Packit 5e46da
        if (bs_seek_byte(bits, pos + len) < 0) {
Packit 5e46da
            return 0;
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
    if (cl->clip.is_atc_delta) {
Packit 5e46da
        // Skip reserved bytes
Packit 5e46da
        bs_skip(bits, 8);
Packit 5e46da
        cl->clip.atc_delta_count = bs_read(bits, 8);
Packit 5e46da
        cl->clip.atc_delta = 
Packit 5e46da
            malloc(cl->clip.atc_delta_count * sizeof(CLPI_ATC_DELTA));
Packit 5e46da
        if (cl->clip.atc_delta_count && !cl->clip.atc_delta) {
Packit 5e46da
            BD_DEBUG(DBG_CRIT, "out of memory\n");
Packit 5e46da
            return 0;
Packit 5e46da
        }
Packit 5e46da
        for (ii = 0; ii < cl->clip.atc_delta_count; ii++) {
Packit 5e46da
            cl->clip.atc_delta[ii].delta = bs_read(bits, 32);
Packit 5e46da
            bs_read_string(bits, cl->clip.atc_delta[ii].file_id, 5);
Packit 5e46da
            bs_read_string(bits, cl->clip.atc_delta[ii].file_code, 4);
Packit 5e46da
            bs_skip(bits, 8);
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    // font info
Packit 5e46da
    if (cl->clip.application_type == 6 /* Sub TS for a sub-path of Text subtitle */) {
Packit 5e46da
        CLPI_FONT_INFO *fi = &cl->clip.font_info;
Packit 5e46da
        bs_skip(bits, 8);
Packit 5e46da
        fi->font_count = bs_read(bits, 8);
Packit 5e46da
        if (fi->font_count) {
Packit 5e46da
            fi->font = malloc(fi->font_count * sizeof(CLPI_FONT));
Packit 5e46da
            if (!fi->font) {
Packit 5e46da
                BD_DEBUG(DBG_CRIT, "out of memory\n");
Packit 5e46da
                return 0;
Packit 5e46da
            }
Packit 5e46da
            for (ii = 0; ii < fi->font_count; ii++) {
Packit 5e46da
                bs_read_string(bits, fi->font[ii].file_id, 5);
Packit 5e46da
                bs_skip(bits, 8);
Packit 5e46da
            }
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    return 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int
Packit 5e46da
_parse_sequence(BITSTREAM *bits, CLPI_CL *cl)
Packit 5e46da
{
Packit 5e46da
    int ii, jj;
Packit 5e46da
Packit 5e46da
    if (bs_seek_byte(bits, cl->sequence_info_start_addr) < 0) {
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    // Skip the length field, and a reserved byte
Packit 5e46da
    bs_skip(bits, 5 * 8);
Packit 5e46da
    // Then get the number of sequences
Packit 5e46da
    cl->sequence.num_atc_seq = bs_read(bits, 8);
Packit 5e46da
Packit 5e46da
    CLPI_ATC_SEQ *atc_seq;
Packit 5e46da
    atc_seq = calloc(cl->sequence.num_atc_seq, sizeof(CLPI_ATC_SEQ));
Packit 5e46da
    cl->sequence.atc_seq = atc_seq;
Packit 5e46da
    if (cl->sequence.num_atc_seq && !atc_seq) {
Packit 5e46da
        BD_DEBUG(DBG_CRIT, "out of memory\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
    for (ii = 0; ii < cl->sequence.num_atc_seq; ii++) {
Packit 5e46da
        atc_seq[ii].spn_atc_start = bs_read(bits, 32);
Packit 5e46da
        atc_seq[ii].num_stc_seq   = bs_read(bits, 8);
Packit 5e46da
        atc_seq[ii].offset_stc_id = bs_read(bits, 8);
Packit 5e46da
Packit 5e46da
        CLPI_STC_SEQ *stc_seq;
Packit 5e46da
        stc_seq = malloc(atc_seq[ii].num_stc_seq * sizeof(CLPI_STC_SEQ));
Packit 5e46da
        if (atc_seq[ii].num_stc_seq && !stc_seq) {
Packit 5e46da
            BD_DEBUG(DBG_CRIT, "out of memory\n");
Packit 5e46da
            return 0;
Packit 5e46da
        }
Packit 5e46da
        atc_seq[ii].stc_seq = stc_seq;
Packit 5e46da
        for (jj = 0; jj < atc_seq[ii].num_stc_seq; jj++) {
Packit 5e46da
            stc_seq[jj].pcr_pid                 = bs_read(bits, 16);
Packit 5e46da
            stc_seq[jj].spn_stc_start           = bs_read(bits, 32);
Packit 5e46da
            stc_seq[jj].presentation_start_time = bs_read(bits, 32);
Packit 5e46da
            stc_seq[jj].presentation_end_time   = bs_read(bits, 32);
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
    return 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int
Packit 5e46da
_parse_program(BITSTREAM *bits, CLPI_PROG_INFO *program)
Packit 5e46da
{
Packit 5e46da
    int ii, jj;
Packit 5e46da
Packit 5e46da
    // Skip the length field, and a reserved byte
Packit 5e46da
    bs_skip(bits, 5 * 8);
Packit 5e46da
    // Then get the number of sequences
Packit 5e46da
    program->num_prog = bs_read(bits, 8);
Packit 5e46da
Packit 5e46da
    CLPI_PROG *progs;
Packit 5e46da
    progs = calloc(program->num_prog, sizeof(CLPI_PROG));
Packit 5e46da
    program->progs = progs;
Packit 5e46da
    if (program->num_prog && !progs) {
Packit 5e46da
        BD_DEBUG(DBG_CRIT, "out of memory\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
    for (ii = 0; ii < program->num_prog; ii++) {
Packit 5e46da
        progs[ii].spn_program_sequence_start = bs_read(bits, 32);
Packit 5e46da
        progs[ii].program_map_pid            = bs_read(bits, 16);
Packit 5e46da
        progs[ii].num_streams                = bs_read(bits, 8);
Packit 5e46da
        progs[ii].num_groups                 = bs_read(bits, 8);
Packit 5e46da
Packit 5e46da
        CLPI_PROG_STREAM *ps;
Packit 5e46da
        ps = calloc(progs[ii].num_streams, sizeof(CLPI_PROG_STREAM));
Packit 5e46da
        if (progs[ii].num_streams && !ps) {
Packit 5e46da
            BD_DEBUG(DBG_CRIT, "out of memory\n");
Packit 5e46da
            return 0;
Packit 5e46da
        }
Packit 5e46da
        progs[ii].streams = ps;
Packit 5e46da
        for (jj = 0; jj < progs[ii].num_streams; jj++) {
Packit 5e46da
            ps[jj].pid = bs_read(bits, 16);
Packit 5e46da
            if (!_parse_stream_attr(bits, &ps[jj])) {
Packit 5e46da
                return 0;
Packit 5e46da
            }
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
    return 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int
Packit 5e46da
_parse_program_info(BITSTREAM *bits, CLPI_CL *cl)
Packit 5e46da
{
Packit 5e46da
    if (bs_seek_byte(bits, cl->program_info_start_addr) < 0) {
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    return _parse_program(bits, &cl->program);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int
Packit 5e46da
_parse_ep_map_stream(BITSTREAM *bits, CLPI_EP_MAP_ENTRY *ee)
Packit 5e46da
{
Packit 5e46da
    uint32_t          fine_start;
Packit 5e46da
    int               ii;
Packit 5e46da
    CLPI_EP_COARSE   * coarse;
Packit 5e46da
    CLPI_EP_FINE     * fine;
Packit 5e46da
Packit 5e46da
    if (bs_seek_byte(bits, ee->ep_map_stream_start_addr) < 0) {
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
    fine_start = bs_read(bits, 32);
Packit 5e46da
Packit 5e46da
    if (bs_avail(bits)/(8*8) < ee->num_ep_coarse) {
Packit 5e46da
        BD_DEBUG(DBG_HDMV|DBG_CRIT, "clpi_parse: unexpected EOF (EP coarse)\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    coarse = malloc(ee->num_ep_coarse * sizeof(CLPI_EP_COARSE));
Packit 5e46da
    ee->coarse = coarse;
Packit 5e46da
    if (ee->num_ep_coarse && !coarse) {
Packit 5e46da
        BD_DEBUG(DBG_CRIT, "out of memory\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
    for (ii = 0; ii < ee->num_ep_coarse; ii++) {
Packit 5e46da
        coarse[ii].ref_ep_fine_id = bs_read(bits, 18);
Packit 5e46da
        coarse[ii].pts_ep         = bs_read(bits, 14);
Packit 5e46da
        coarse[ii].spn_ep         = bs_read(bits, 32);
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    if (bs_seek_byte(bits, ee->ep_map_stream_start_addr+fine_start) < 0) {
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    if (bs_avail(bits)/(8*4) < ee->num_ep_fine) {
Packit 5e46da
        BD_DEBUG(DBG_HDMV|DBG_CRIT, "clpi_parse: unexpected EOF (EP fine)\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    fine = malloc(ee->num_ep_fine * sizeof(CLPI_EP_FINE));
Packit 5e46da
    ee->fine = fine;
Packit 5e46da
    if (ee->num_ep_fine && !fine) {
Packit 5e46da
        BD_DEBUG(DBG_CRIT, "out of memory\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
    for (ii = 0; ii < ee->num_ep_fine; ii++) {
Packit 5e46da
        fine[ii].is_angle_change_point = bs_read(bits, 1);
Packit 5e46da
        fine[ii].i_end_position_offset = bs_read(bits, 3);
Packit 5e46da
        fine[ii].pts_ep                = bs_read(bits, 11);
Packit 5e46da
        fine[ii].spn_ep                = bs_read(bits, 17);
Packit 5e46da
    }
Packit 5e46da
    return 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int
Packit 5e46da
_parse_cpi(BITSTREAM *bits, CLPI_CPI *cpi)
Packit 5e46da
{
Packit 5e46da
    int ii;
Packit 5e46da
    uint32_t ep_map_pos, len;
Packit 5e46da
Packit 5e46da
    len = bs_read(bits, 32);
Packit 5e46da
    if (len == 0) {
Packit 5e46da
        return 1;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    bs_skip(bits, 12);
Packit 5e46da
    cpi->type = bs_read(bits, 4);
Packit 5e46da
    ep_map_pos = (uint32_t)(bs_pos(bits) >> 3);
Packit 5e46da
Packit 5e46da
    // EP Map starts here
Packit 5e46da
    bs_skip(bits, 8);
Packit 5e46da
    cpi->num_stream_pid = bs_read(bits, 8);
Packit 5e46da
Packit 5e46da
    CLPI_EP_MAP_ENTRY *entry;
Packit 5e46da
    entry = calloc(cpi->num_stream_pid, sizeof(CLPI_EP_MAP_ENTRY));
Packit 5e46da
    cpi->entry = entry;
Packit 5e46da
    if (cpi->num_stream_pid && !entry) {
Packit 5e46da
        BD_DEBUG(DBG_CRIT, "out of memory\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
    for (ii = 0; ii < cpi->num_stream_pid; ii++) {
Packit 5e46da
        entry[ii].pid                      = bs_read(bits, 16);
Packit 5e46da
        bs_skip(bits, 10);
Packit 5e46da
        entry[ii].ep_stream_type           = bs_read(bits, 4);
Packit 5e46da
        entry[ii].num_ep_coarse            = bs_read(bits, 16);
Packit 5e46da
        entry[ii].num_ep_fine              = bs_read(bits, 18);
Packit 5e46da
        entry[ii].ep_map_stream_start_addr = bs_read(bits, 32) + ep_map_pos;
Packit 5e46da
    }
Packit 5e46da
    for (ii = 0; ii < cpi->num_stream_pid; ii++) {
Packit 5e46da
        if (!_parse_ep_map_stream(bits, &cpi->entry[ii])) {
Packit 5e46da
            return 0;
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
    return 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int
Packit 5e46da
_parse_cpi_info(BITSTREAM *bits, CLPI_CL *cl)
Packit 5e46da
{
Packit 5e46da
    if (bs_seek_byte(bits, cl->cpi_start_addr) < 0) {
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    return _parse_cpi(bits, &cl->cpi);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
uint32_t
Packit 5e46da
clpi_find_stc_spn(const CLPI_CL *cl, uint8_t stc_id)
Packit 5e46da
{
Packit 5e46da
    int ii;
Packit 5e46da
    CLPI_ATC_SEQ *atc;
Packit 5e46da
Packit 5e46da
    for (ii = 0; ii < cl->sequence.num_atc_seq; ii++) {
Packit 5e46da
        atc = &cl->sequence.atc_seq[ii];
Packit 5e46da
        if (stc_id < atc->offset_stc_id + atc->num_stc_seq) {
Packit 5e46da
            return atc->stc_seq[stc_id - atc->offset_stc_id].spn_stc_start;
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
    return 0;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
// Looks up the start packet number for the timestamp
Packit 5e46da
// Returns the spn for the entry that is closest to but
Packit 5e46da
// before the given timestamp
Packit 5e46da
uint32_t
Packit 5e46da
clpi_lookup_spn(const CLPI_CL *cl, uint32_t timestamp, int before, uint8_t stc_id)
Packit 5e46da
{
Packit 5e46da
    const CLPI_EP_MAP_ENTRY *entry;
Packit 5e46da
    const CLPI_CPI *cpi = &cl->cpi;
Packit 5e46da
    int ii, jj;
Packit 5e46da
    uint32_t coarse_pts, pts; // 45khz timestamps
Packit 5e46da
    uint32_t spn, coarse_spn, stc_spn;
Packit 5e46da
    int start, end;
Packit 5e46da
    int ref;
Packit 5e46da
Packit 5e46da
    if (cpi->num_stream_pid < 1 || !cpi->entry) {
Packit 5e46da
        if (before) {
Packit 5e46da
            return 0;
Packit 5e46da
        }
Packit 5e46da
        return cl->clip.num_source_packets;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    // Assumes that there is only one pid of interest
Packit 5e46da
    entry = &cpi->entry[0];
Packit 5e46da
Packit 5e46da
    // Use sequence info to find spn_stc_start before doing
Packit 5e46da
    // PTS search. The spn_stc_start defines the point in
Packit 5e46da
    // the EP map to start searching.
Packit 5e46da
    stc_spn = clpi_find_stc_spn(cl, stc_id);
Packit 5e46da
    for (ii = 0; ii < entry->num_ep_coarse; ii++) {
Packit 5e46da
        ref = entry->coarse[ii].ref_ep_fine_id;
Packit 5e46da
        if (entry->coarse[ii].spn_ep >= stc_spn) {
Packit 5e46da
            // The desired starting point is either after this point
Packit 5e46da
            // or in the middle of the previous coarse entry
Packit 5e46da
            break;
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
    if (ii >= entry->num_ep_coarse) {
Packit 5e46da
        return cl->clip.num_source_packets;
Packit 5e46da
    }
Packit 5e46da
    pts = ((uint64_t)(entry->coarse[ii].pts_ep & ~0x01) << 18) +
Packit 5e46da
          ((uint64_t)entry->fine[ref].pts_ep << 8);
Packit 5e46da
    if (pts > timestamp && ii) {
Packit 5e46da
        // The starting point and desired PTS is in the previous coarse entry
Packit 5e46da
        ii--;
Packit 5e46da
        coarse_pts = (uint32_t)(entry->coarse[ii].pts_ep & ~0x01) << 18;
Packit 5e46da
        coarse_spn = entry->coarse[ii].spn_ep;
Packit 5e46da
        start = entry->coarse[ii].ref_ep_fine_id;
Packit 5e46da
        end = entry->coarse[ii+1].ref_ep_fine_id;
Packit 5e46da
        // Find a fine entry that has bothe spn > stc_spn and ptc > timestamp
Packit 5e46da
        for (jj = start; jj < end; jj++) {
Packit 5e46da
Packit 5e46da
            pts = coarse_pts + ((uint32_t)entry->fine[jj].pts_ep << 8);
Packit 5e46da
            spn = (coarse_spn & ~0x1FFFF) + entry->fine[jj].spn_ep;
Packit 5e46da
            if (stc_spn >= spn && pts > timestamp)
Packit 5e46da
                break;
Packit 5e46da
        }
Packit 5e46da
        goto done;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    // If we've gotten this far, the desired timestamp is somewhere
Packit 5e46da
    // after the coarse entry we found the stc_spn in.
Packit 5e46da
    start = ii;
Packit 5e46da
    for (ii = start; ii < entry->num_ep_coarse; ii++) {
Packit 5e46da
        ref = entry->coarse[ii].ref_ep_fine_id;
Packit 5e46da
        pts = ((uint64_t)(entry->coarse[ii].pts_ep & ~0x01) << 18) +
Packit 5e46da
                ((uint64_t)entry->fine[ref].pts_ep << 8);
Packit 5e46da
        if (pts > timestamp) {
Packit 5e46da
            break;
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
    // If the timestamp is before the first entry, then return
Packit 5e46da
    // the beginning of the clip
Packit 5e46da
    if (ii == 0) {
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
    ii--;
Packit 5e46da
    coarse_pts = (uint32_t)(entry->coarse[ii].pts_ep & ~0x01) << 18;
Packit 5e46da
    start = entry->coarse[ii].ref_ep_fine_id;
Packit 5e46da
    if (ii < entry->num_ep_coarse - 1) {
Packit 5e46da
        end = entry->coarse[ii+1].ref_ep_fine_id;
Packit 5e46da
    } else {
Packit 5e46da
        end = entry->num_ep_fine;
Packit 5e46da
    }
Packit 5e46da
    for (jj = start; jj < end; jj++) {
Packit 5e46da
Packit 5e46da
        pts = coarse_pts + ((uint32_t)entry->fine[jj].pts_ep << 8);
Packit 5e46da
        if (pts > timestamp)
Packit 5e46da
            break;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
done:
Packit 5e46da
    if (before) {
Packit 5e46da
        jj--;
Packit 5e46da
    }
Packit 5e46da
    if (jj == end) {
Packit 5e46da
        ii++;
Packit 5e46da
        if (ii >= entry->num_ep_coarse) {
Packit 5e46da
            // End of file
Packit 5e46da
            return cl->clip.num_source_packets;
Packit 5e46da
        }
Packit 5e46da
        jj = entry->coarse[ii].ref_ep_fine_id;
Packit 5e46da
    }
Packit 5e46da
    spn = (entry->coarse[ii].spn_ep & ~0x1FFFF) + entry->fine[jj].spn_ep;
Packit 5e46da
    return spn;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
// Looks up the start packet number that is closest to the requested packet
Packit 5e46da
// Returns the spn for the entry that is closest to but
Packit 5e46da
// before the given packet
Packit 5e46da
uint32_t
Packit 5e46da
clpi_access_point(const CLPI_CL *cl, uint32_t pkt, int next, int angle_change, uint32_t *time)
Packit 5e46da
{
Packit 5e46da
    const CLPI_EP_MAP_ENTRY *entry;
Packit 5e46da
    const CLPI_CPI *cpi = &cl->cpi;
Packit 5e46da
    int ii, jj;
Packit 5e46da
    uint32_t coarse_spn, spn;
Packit 5e46da
    int start, end;
Packit 5e46da
    int ref;
Packit 5e46da
Packit 5e46da
    // Assumes that there is only one pid of interest
Packit 5e46da
    entry = &cpi->entry[0];
Packit 5e46da
Packit 5e46da
    for (ii = 0; ii < entry->num_ep_coarse; ii++) {
Packit 5e46da
        ref = entry->coarse[ii].ref_ep_fine_id;
Packit 5e46da
        spn = (entry->coarse[ii].spn_ep & ~0x1FFFF) + entry->fine[ref].spn_ep;
Packit 5e46da
        if (spn > pkt) {
Packit 5e46da
            break;
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
    // If the timestamp is before the first entry, then return
Packit 5e46da
    // the beginning of the clip
Packit 5e46da
    if (ii == 0) {
Packit 5e46da
        *time = 0;
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
    ii--;
Packit 5e46da
    coarse_spn = (entry->coarse[ii].spn_ep & ~0x1FFFF);
Packit 5e46da
    start = entry->coarse[ii].ref_ep_fine_id;
Packit 5e46da
    if (ii < entry->num_ep_coarse - 1) {
Packit 5e46da
        end = entry->coarse[ii+1].ref_ep_fine_id;
Packit 5e46da
    } else {
Packit 5e46da
        end = entry->num_ep_fine;
Packit 5e46da
    }
Packit 5e46da
    for (jj = start; jj < end; jj++) {
Packit 5e46da
Packit 5e46da
        spn = coarse_spn + entry->fine[jj].spn_ep;
Packit 5e46da
        if (spn >= pkt) {
Packit 5e46da
            break;
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
    if (jj == end && next) {
Packit 5e46da
        ii++;
Packit 5e46da
        jj = 0;
Packit 5e46da
    } else if (spn != pkt && !next) {
Packit 5e46da
        jj--;
Packit 5e46da
    }
Packit 5e46da
    if (ii == entry->num_ep_coarse) {
Packit 5e46da
        *time = 0;
Packit 5e46da
        return cl->clip.num_source_packets;
Packit 5e46da
    }
Packit 5e46da
    coarse_spn = (entry->coarse[ii].spn_ep & ~0x1FFFF);
Packit 5e46da
    if (angle_change) {
Packit 5e46da
        // Keep looking till there's an angle change point
Packit 5e46da
        for (; jj < end; jj++) {
Packit 5e46da
Packit 5e46da
            if (entry->fine[jj].is_angle_change_point) {
Packit 5e46da
                *time = ((uint64_t)(entry->coarse[ii].pts_ep & ~0x01) << 18) +
Packit 5e46da
                        ((uint64_t)entry->fine[jj].pts_ep << 8);
Packit 5e46da
                return coarse_spn + entry->fine[jj].spn_ep;
Packit 5e46da
            }
Packit 5e46da
        }
Packit 5e46da
        for (ii++; ii < entry->num_ep_coarse; ii++) {
Packit 5e46da
            start = entry->coarse[ii].ref_ep_fine_id;
Packit 5e46da
            if (ii < entry->num_ep_coarse - 1) {
Packit 5e46da
                end = entry->coarse[ii+1].ref_ep_fine_id;
Packit 5e46da
            } else {
Packit 5e46da
                end = entry->num_ep_fine;
Packit 5e46da
            }
Packit 5e46da
            for (jj = start; jj < end; jj++) {
Packit 5e46da
Packit 5e46da
                if (entry->fine[jj].is_angle_change_point) {
Packit 5e46da
                    *time = ((uint64_t)(entry->coarse[ii].pts_ep & ~0x01) << 18) +
Packit 5e46da
                            ((uint64_t)entry->fine[jj].pts_ep << 8);
Packit 5e46da
                    return coarse_spn + entry->fine[jj].spn_ep;
Packit 5e46da
                }
Packit 5e46da
            }
Packit 5e46da
        }
Packit 5e46da
        *time = 0;
Packit 5e46da
        return cl->clip.num_source_packets;
Packit 5e46da
    }
Packit 5e46da
    *time = ((uint64_t)(entry->coarse[ii].pts_ep & ~0x01) << 18) +
Packit 5e46da
            ((uint64_t)entry->fine[jj].pts_ep << 8);
Packit 5e46da
    return coarse_spn + entry->fine[jj].spn_ep;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int
Packit 5e46da
_parse_extent_start_points(BITSTREAM *bits, CLPI_EXTENT_START *es)
Packit 5e46da
{
Packit 5e46da
    unsigned int ii;
Packit 5e46da
Packit 5e46da
    bs_skip(bits, 32); // length
Packit 5e46da
    es->num_point = bs_read(bits, 32);
Packit 5e46da
Packit 5e46da
    es->point = calloc(es->num_point, sizeof(uint32_t));
Packit 5e46da
    if (es->num_point && !es->point) {
Packit 5e46da
        es->num_point = 0;
Packit 5e46da
        BD_DEBUG(DBG_CRIT, "out of memory\n");
Packit 5e46da
        return 0;
Packit 5e46da
    }
Packit 5e46da
    for (ii = 0; ii < es->num_point; ii++) {
Packit 5e46da
        es->point[ii] = bs_read(bits, 32);
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    return 1;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static int _parse_clpi_extension(BITSTREAM *bits, int id1, int id2, void *handle)
Packit 5e46da
{
Packit 5e46da
    CLPI_CL *cl = (CLPI_CL*)handle;
Packit 5e46da
Packit 5e46da
    if (id1 == 1) {
Packit 5e46da
        if (id2 == 2) {
Packit 5e46da
            // LPCM down mix coefficient
Packit 5e46da
            //_parse_lpcm_down_mix_coeff(bits, &cl->lpcm_down_mix_coeff);
Packit 5e46da
            return 0;
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    if (id1 == 2) {
Packit 5e46da
        if (id2 == 4) {
Packit 5e46da
            // Extent start point
Packit 5e46da
            return _parse_extent_start_points(bits, &cl->extent_start);
Packit 5e46da
        }
Packit 5e46da
        if (id2 == 5) {
Packit 5e46da
            // ProgramInfo SS
Packit 5e46da
            return _parse_program(bits, &cl->program_ss);
Packit 5e46da
        }
Packit 5e46da
        if (id2 == 6) {
Packit 5e46da
            // CPI SS
Packit 5e46da
            return _parse_cpi(bits, &cl->cpi_ss);
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_clpi_extension(): unhandled extension %d.%d\n", id1, id2);
Packit 5e46da
    return 0;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void
Packit 5e46da
_clean_program(CLPI_PROG_INFO *p)
Packit 5e46da
{
Packit 5e46da
    int ii;
Packit 5e46da
Packit 5e46da
    if (p && p->progs) {
Packit 5e46da
        for (ii = 0; ii < p->num_prog; ii++) {
Packit 5e46da
            X_FREE(p->progs[ii].streams);
Packit 5e46da
        }
Packit 5e46da
        X_FREE(p->progs);
Packit 5e46da
    }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void
Packit 5e46da
_clean_cpi(CLPI_CPI *cpi)
Packit 5e46da
{
Packit 5e46da
    int ii;
Packit 5e46da
Packit 5e46da
    if (cpi && cpi->entry) {
Packit 5e46da
        for (ii = 0; ii < cpi->num_stream_pid; ii++) {
Packit 5e46da
            X_FREE(cpi->entry[ii].coarse);
Packit 5e46da
            X_FREE(cpi->entry[ii].fine);
Packit 5e46da
        }
Packit 5e46da
        X_FREE(cpi->entry);
Packit 5e46da
    }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static void
Packit 5e46da
_clpi_free(CLPI_CL *cl)
Packit 5e46da
{
Packit 5e46da
    int ii;
Packit 5e46da
Packit 5e46da
    X_FREE(cl->clip.atc_delta);
Packit 5e46da
    X_FREE(cl->clip.font_info.font);
Packit 5e46da
Packit 5e46da
    if (cl->sequence.atc_seq) {
Packit 5e46da
        for (ii = 0; ii < cl->sequence.num_atc_seq; ii++) {
Packit 5e46da
            X_FREE(cl->sequence.atc_seq[ii].stc_seq);
Packit 5e46da
        }
Packit 5e46da
Packit 5e46da
        X_FREE(cl->sequence.atc_seq);
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    _clean_program(&cl->program);
Packit 5e46da
    _clean_cpi(&cl->cpi);
Packit 5e46da
Packit 5e46da
    X_FREE(cl->extent_start.point);
Packit 5e46da
Packit 5e46da
    _clean_program(&cl->program_ss);
Packit 5e46da
    _clean_cpi(&cl->cpi_ss);
Packit 5e46da
Packit 5e46da
    X_FREE(cl);
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
void
Packit 5e46da
clpi_free(CLPI_CL **cl)
Packit 5e46da
{
Packit 5e46da
    if (*cl) {
Packit 5e46da
        _clpi_free(*cl);
Packit 5e46da
        *cl = NULL;
Packit 5e46da
    }
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static CLPI_CL*
Packit 5e46da
_clpi_parse(BD_FILE_H *fp)
Packit 5e46da
{
Packit 5e46da
    BITSTREAM  bits;
Packit 5e46da
    CLPI_CL   *cl;
Packit 5e46da
Packit 5e46da
    if (bs_init(&bits, fp) < 0) {
Packit 5e46da
        BD_DEBUG(DBG_NAV, "?????.clpi: read error\n");
Packit 5e46da
        return NULL;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    cl = calloc(1, sizeof(CLPI_CL));
Packit 5e46da
    if (cl == NULL) {
Packit 5e46da
        BD_DEBUG(DBG_CRIT, "out of memory\n");
Packit 5e46da
        return NULL;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    if (!_parse_header(&bits, cl)) {
Packit 5e46da
        _clpi_free(cl);
Packit 5e46da
        return NULL;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    if (cl->ext_data_start_addr > 0) {
Packit 5e46da
        bdmv_parse_extension_data(&bits,
Packit 5e46da
                                   cl->ext_data_start_addr,
Packit 5e46da
                                   _parse_clpi_extension,
Packit 5e46da
                                   cl);
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    if (!_parse_clipinfo(&bits, cl)) {
Packit 5e46da
        _clpi_free(cl);
Packit 5e46da
        return NULL;
Packit 5e46da
    }
Packit 5e46da
    if (!_parse_sequence(&bits, cl)) {
Packit 5e46da
        _clpi_free(cl);
Packit 5e46da
        return NULL;
Packit 5e46da
    }
Packit 5e46da
    if (!_parse_program_info(&bits, cl)) {
Packit 5e46da
        _clpi_free(cl);
Packit 5e46da
        return NULL;
Packit 5e46da
    }
Packit 5e46da
    if (!_parse_cpi_info(&bits, cl)) {
Packit 5e46da
        _clpi_free(cl);
Packit 5e46da
        return NULL;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    return cl;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
CLPI_CL*
Packit 5e46da
clpi_parse(const char *path)
Packit 5e46da
{
Packit 5e46da
    BD_FILE_H *fp;
Packit 5e46da
    CLPI_CL   *cl;
Packit 5e46da
Packit 5e46da
    fp = file_open(path, "rb");
Packit 5e46da
    if (!fp) {
Packit 5e46da
        BD_DEBUG(DBG_NAV | DBG_CRIT, "Failed to open %s\n", path);
Packit 5e46da
        return NULL;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    cl = _clpi_parse(fp);
Packit 5e46da
    file_close(fp);
Packit 5e46da
    return cl;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
static CLPI_CL*
Packit 5e46da
_clpi_get(BD_DISC *disc, const char *dir, const char *file)
Packit 5e46da
{
Packit 5e46da
    BD_FILE_H *fp;
Packit 5e46da
    CLPI_CL   *cl;
Packit 5e46da
Packit 5e46da
    fp = disc_open_file(disc, dir, file);
Packit 5e46da
    if (!fp) {
Packit 5e46da
        return NULL;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    cl = _clpi_parse(fp);
Packit 5e46da
    file_close(fp);
Packit 5e46da
    return cl;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
CLPI_CL*
Packit 5e46da
clpi_get(BD_DISC *disc, const char *file)
Packit 5e46da
{
Packit 5e46da
    CLPI_CL *cl;
Packit 5e46da
Packit 5e46da
    cl = _clpi_get(disc, "BDMV" DIR_SEP "CLIPINF", file);
Packit 5e46da
    if (cl) {
Packit 5e46da
        return cl;
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    /* if failed, try backup file */
Packit 5e46da
    cl = _clpi_get(disc, "BDMV" DIR_SEP "BACKUP" DIR_SEP "CLIPINF", file);
Packit 5e46da
    return cl;
Packit 5e46da
}
Packit 5e46da
Packit 5e46da
CLPI_CL*
Packit 5e46da
clpi_copy(const CLPI_CL* src_cl)
Packit 5e46da
{
Packit 5e46da
    CLPI_CL* dest_cl = NULL;
Packit 5e46da
    int ii, jj;
Packit 5e46da
Packit 5e46da
    if (src_cl) {
Packit 5e46da
        dest_cl = (CLPI_CL*) calloc(1, sizeof(CLPI_CL));
Packit 5e46da
        if (!dest_cl) {
Packit 5e46da
            goto fail;
Packit 5e46da
        }
Packit 5e46da
        dest_cl->clip.clip_stream_type = src_cl->clip.clip_stream_type;
Packit 5e46da
        dest_cl->clip.application_type = src_cl->clip.application_type;
Packit 5e46da
        dest_cl->clip.is_atc_delta = src_cl->clip.is_atc_delta;
Packit 5e46da
        dest_cl->clip.atc_delta_count = src_cl->clip.atc_delta_count;
Packit 5e46da
        dest_cl->clip.ts_recording_rate = src_cl->clip.ts_recording_rate;
Packit 5e46da
        dest_cl->clip.num_source_packets = src_cl->clip.num_source_packets;
Packit 5e46da
        dest_cl->clip.ts_type_info.validity = src_cl->clip.ts_type_info.validity;
Packit 5e46da
        memcpy(dest_cl->clip.ts_type_info.format_id, src_cl->clip.ts_type_info.format_id, 5);
Packit 5e46da
        dest_cl->clip.atc_delta = malloc(src_cl->clip.atc_delta_count * sizeof(CLPI_ATC_DELTA));
Packit 5e46da
        if (src_cl->clip.atc_delta_count && !dest_cl->clip.atc_delta) {
Packit 5e46da
            goto fail;
Packit 5e46da
        }
Packit 5e46da
        for (ii = 0; ii < src_cl->clip.atc_delta_count; ii++) {
Packit 5e46da
            dest_cl->clip.atc_delta[ii].delta =  src_cl->clip.atc_delta[ii].delta;
Packit 5e46da
            memcpy(dest_cl->clip.atc_delta[ii].file_id, src_cl->clip.atc_delta[ii].file_id, 6);
Packit 5e46da
            memcpy(dest_cl->clip.atc_delta[ii].file_code, src_cl->clip.atc_delta[ii].file_code, 5);
Packit 5e46da
        }
Packit 5e46da
Packit 5e46da
        dest_cl->sequence.num_atc_seq = src_cl->sequence.num_atc_seq;
Packit 5e46da
        dest_cl->sequence.atc_seq = calloc(src_cl->sequence.num_atc_seq, sizeof(CLPI_ATC_SEQ));
Packit 5e46da
        if (dest_cl->sequence.num_atc_seq && !dest_cl->sequence.atc_seq) {
Packit 5e46da
            goto fail;
Packit 5e46da
        }
Packit 5e46da
        for (ii = 0; ii < src_cl->sequence.num_atc_seq; ii++) {
Packit 5e46da
            dest_cl->sequence.atc_seq[ii].spn_atc_start = src_cl->sequence.atc_seq[ii].spn_atc_start;
Packit 5e46da
            dest_cl->sequence.atc_seq[ii].offset_stc_id = src_cl->sequence.atc_seq[ii].offset_stc_id;
Packit 5e46da
            dest_cl->sequence.atc_seq[ii].num_stc_seq = src_cl->sequence.atc_seq[ii].num_stc_seq;
Packit 5e46da
            dest_cl->sequence.atc_seq[ii].stc_seq = malloc(src_cl->sequence.atc_seq[ii].num_stc_seq * sizeof(CLPI_STC_SEQ));
Packit 5e46da
            if (dest_cl->sequence.atc_seq[ii].num_stc_seq && !dest_cl->sequence.atc_seq[ii].stc_seq) {
Packit 5e46da
                goto fail;
Packit 5e46da
            }
Packit 5e46da
            for (jj = 0; jj < src_cl->sequence.atc_seq[ii].num_stc_seq; jj++) {
Packit 5e46da
                dest_cl->sequence.atc_seq[ii].stc_seq[jj].spn_stc_start = src_cl->sequence.atc_seq[ii].stc_seq[jj].spn_stc_start;
Packit 5e46da
                dest_cl->sequence.atc_seq[ii].stc_seq[jj].pcr_pid = src_cl->sequence.atc_seq[ii].stc_seq[jj].pcr_pid;
Packit 5e46da
                dest_cl->sequence.atc_seq[ii].stc_seq[jj].presentation_start_time = src_cl->sequence.atc_seq[ii].stc_seq[jj].presentation_start_time;
Packit 5e46da
                dest_cl->sequence.atc_seq[ii].stc_seq[jj].presentation_end_time = src_cl->sequence.atc_seq[ii].stc_seq[jj].presentation_end_time;
Packit 5e46da
            }
Packit 5e46da
        }
Packit 5e46da
Packit 5e46da
        dest_cl->program.num_prog = src_cl->program.num_prog;
Packit 5e46da
        dest_cl->program.progs = calloc(src_cl->program.num_prog, sizeof(CLPI_PROG));
Packit 5e46da
        if (dest_cl->program.num_prog && !dest_cl->program.progs) {
Packit 5e46da
            goto fail;
Packit 5e46da
        }
Packit 5e46da
        for (ii = 0; ii < src_cl->program.num_prog; ii++) {
Packit 5e46da
            dest_cl->program.progs[ii].spn_program_sequence_start = src_cl->program.progs[ii].spn_program_sequence_start;
Packit 5e46da
            dest_cl->program.progs[ii].program_map_pid = src_cl->program.progs[ii].program_map_pid;
Packit 5e46da
            dest_cl->program.progs[ii].num_streams = src_cl->program.progs[ii].num_streams;
Packit 5e46da
            dest_cl->program.progs[ii].num_groups = src_cl->program.progs[ii].num_groups;
Packit 5e46da
            dest_cl->program.progs[ii].streams = malloc(src_cl->program.progs[ii].num_streams * sizeof(CLPI_PROG_STREAM));
Packit 5e46da
            if (src_cl->program.progs[ii].num_streams && !dest_cl->program.progs[ii].streams) {
Packit 5e46da
                goto fail;
Packit 5e46da
            }
Packit 5e46da
            for (jj = 0; jj < src_cl->program.progs[ii].num_streams; jj++) {
Packit 5e46da
                dest_cl->program.progs[ii].streams[jj].coding_type = src_cl->program.progs[ii].streams[jj].coding_type;
Packit 5e46da
                dest_cl->program.progs[ii].streams[jj].pid = src_cl->program.progs[ii].streams[jj].pid;
Packit 5e46da
                dest_cl->program.progs[ii].streams[jj].format = src_cl->program.progs[ii].streams[jj].format;
Packit 5e46da
                dest_cl->program.progs[ii].streams[jj].rate = src_cl->program.progs[ii].streams[jj].rate;
Packit 5e46da
                dest_cl->program.progs[ii].streams[jj].aspect = src_cl->program.progs[ii].streams[jj].aspect;
Packit 5e46da
                dest_cl->program.progs[ii].streams[jj].oc_flag = src_cl->program.progs[ii].streams[jj].oc_flag;
Packit 5e46da
                dest_cl->program.progs[ii].streams[jj].char_code = src_cl->program.progs[ii].streams[jj].char_code;
Packit 5e46da
                memcpy(dest_cl->program.progs[ii].streams[jj].lang,src_cl->program.progs[ii].streams[jj].lang,4);
Packit 5e46da
            }
Packit 5e46da
        }
Packit 5e46da
Packit 5e46da
        dest_cl->cpi.num_stream_pid = src_cl->cpi.num_stream_pid;
Packit 5e46da
        dest_cl->cpi.entry = calloc(src_cl->cpi.num_stream_pid, sizeof(CLPI_EP_MAP_ENTRY));
Packit 5e46da
        if (dest_cl->cpi.num_stream_pid && !dest_cl->cpi.entry) {
Packit 5e46da
            goto fail;
Packit 5e46da
        }
Packit 5e46da
        for (ii = 0; ii < dest_cl->cpi.num_stream_pid; ii++) {
Packit 5e46da
            dest_cl->cpi.entry[ii].pid = src_cl->cpi.entry[ii].pid;
Packit 5e46da
            dest_cl->cpi.entry[ii].ep_stream_type = src_cl->cpi.entry[ii].ep_stream_type;
Packit 5e46da
            dest_cl->cpi.entry[ii].num_ep_coarse = src_cl->cpi.entry[ii].num_ep_coarse;
Packit 5e46da
            dest_cl->cpi.entry[ii].num_ep_fine = src_cl->cpi.entry[ii].num_ep_fine;
Packit 5e46da
            dest_cl->cpi.entry[ii].ep_map_stream_start_addr = src_cl->cpi.entry[ii].ep_map_stream_start_addr;
Packit 5e46da
            dest_cl->cpi.entry[ii].coarse = malloc(src_cl->cpi.entry[ii].num_ep_coarse * sizeof(CLPI_EP_COARSE));
Packit 5e46da
            if (dest_cl->cpi.entry[ii].num_ep_coarse && !dest_cl->cpi.entry[ii].coarse) {
Packit 5e46da
                goto fail;
Packit 5e46da
            }
Packit 5e46da
            for (jj = 0; jj < src_cl->cpi.entry[ii].num_ep_coarse; jj++) {
Packit 5e46da
                dest_cl->cpi.entry[ii].coarse[jj].ref_ep_fine_id = src_cl->cpi.entry[ii].coarse[jj].ref_ep_fine_id;
Packit 5e46da
                dest_cl->cpi.entry[ii].coarse[jj].pts_ep = src_cl->cpi.entry[ii].coarse[jj].pts_ep;
Packit 5e46da
                dest_cl->cpi.entry[ii].coarse[jj].spn_ep = src_cl->cpi.entry[ii].coarse[jj].spn_ep;
Packit 5e46da
            }
Packit 5e46da
            dest_cl->cpi.entry[ii].fine = malloc(src_cl->cpi.entry[ii].num_ep_fine * sizeof(CLPI_EP_FINE));
Packit 5e46da
            if (dest_cl->cpi.entry[ii].num_ep_fine && !dest_cl->cpi.entry[ii].fine) {
Packit 5e46da
                goto fail;
Packit 5e46da
            }
Packit 5e46da
            for (jj = 0; jj < src_cl->cpi.entry[ii].num_ep_fine; jj++) {
Packit 5e46da
                dest_cl->cpi.entry[ii].fine[jj].is_angle_change_point = src_cl->cpi.entry[ii].fine[jj].is_angle_change_point;
Packit 5e46da
                dest_cl->cpi.entry[ii].fine[jj].i_end_position_offset = src_cl->cpi.entry[ii].fine[jj].i_end_position_offset;
Packit 5e46da
                dest_cl->cpi.entry[ii].fine[jj].pts_ep = src_cl->cpi.entry[ii].fine[jj].pts_ep;
Packit 5e46da
                dest_cl->cpi.entry[ii].fine[jj].spn_ep = src_cl->cpi.entry[ii].fine[jj].spn_ep;
Packit 5e46da
            }
Packit 5e46da
        }
Packit 5e46da
Packit 5e46da
        dest_cl->clip.font_info.font_count = src_cl->clip.font_info.font_count;
Packit 5e46da
        if (dest_cl->clip.font_info.font_count) {
Packit 5e46da
            dest_cl->clip.font_info.font = malloc(dest_cl->clip.font_info.font_count * sizeof(CLPI_FONT));
Packit 5e46da
            if (!dest_cl->clip.font_info.font) {
Packit 5e46da
                goto fail;
Packit 5e46da
            }
Packit 5e46da
            memcpy(dest_cl->clip.font_info.font, src_cl->clip.font_info.font, dest_cl->clip.font_info.font_count * sizeof(CLPI_FONT));
Packit 5e46da
        }
Packit 5e46da
    }
Packit 5e46da
Packit 5e46da
    return dest_cl;
Packit 5e46da
Packit 5e46da
 fail:
Packit 5e46da
    BD_DEBUG(DBG_CRIT, "out of memory\n");
Packit 5e46da
    clpi_free(&dest_cl);
Packit 5e46da
    return NULL;
Packit 5e46da
}