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