|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* This file is part of libbluray
|
|
Packit |
5e46da |
* Copyright (C) 2009-2010 John Stebbins
|
|
Packit |
5e46da |
* Copyright (C) 2012 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 "mpls_parse.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "extdata_parse.h"
|
|
Packit |
5e46da |
#include "bdmv_parse.h"
|
|
Packit |
5e46da |
#include "uo_mask.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/logging.h"
|
|
Packit |
5e46da |
#include "util/macro.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include <stdlib.h>
|
|
Packit |
5e46da |
#include <string.h>
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#define MPLS_SIG1 ('M' << 24 | 'P' << 16 | 'L' << 8 | 'S')
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int
|
|
Packit |
5e46da |
_parse_uo(BITSTREAM *bits, BD_UO_MASK *uo)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
uint8_t buf[8];
|
|
Packit |
5e46da |
bs_read_bytes(bits, buf, 8);
|
|
Packit |
5e46da |
return uo_mask_parse(buf, uo);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int
|
|
Packit |
5e46da |
_parse_appinfo(BITSTREAM *bits, MPLS_AI *ai)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int64_t /*pos,*/ len;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!bs_is_align(bits, 0x07)) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_appinfo: alignment error\n");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
//pos = bs_pos(bits) >> 3;
|
|
Packit |
5e46da |
len = bs_read(bits, 32);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bs_avail(bits) < len * 8) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_appinfo: unexpected end of file\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Reserved
|
|
Packit |
5e46da |
bs_skip(bits, 8);
|
|
Packit |
5e46da |
ai->playback_type = bs_read(bits, 8);
|
|
Packit |
5e46da |
if (ai->playback_type == 2 || ai->playback_type == 3) {
|
|
Packit |
5e46da |
ai->playback_count = bs_read(bits, 16);
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
// Reserved
|
|
Packit |
5e46da |
bs_skip(bits, 16);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
_parse_uo(bits, &ai->uo_mask);
|
|
Packit |
5e46da |
ai->random_access_flag = bs_read(bits, 1);
|
|
Packit |
5e46da |
ai->audio_mix_flag = bs_read(bits, 1);
|
|
Packit |
5e46da |
ai->lossless_bypass_flag = bs_read(bits, 1);
|
|
Packit |
5e46da |
#if 0
|
|
Packit |
5e46da |
// Reserved
|
|
Packit |
5e46da |
bs_skip(bits, 13);
|
|
Packit |
5e46da |
bs_seek_byte(bits, pos + len);
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int
|
|
Packit |
5e46da |
_parse_header(BITSTREAM *bits, MPLS_PL *pl)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
pl->type_indicator = MPLS_SIG1;
|
|
Packit |
5e46da |
if (!bdmv_parse_header(bits, pl->type_indicator, &pl->type_indicator2)) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bs_avail(bits) < 5 * 32 + 160) {
|
|
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 |
pl->list_pos = bs_read(bits, 32);
|
|
Packit |
5e46da |
pl->mark_pos = bs_read(bits, 32);
|
|
Packit |
5e46da |
pl->ext_pos = bs_read(bits, 32);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Skip 160 reserved bits
|
|
Packit |
5e46da |
bs_skip(bits, 160);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_parse_appinfo(bits, &pl->app_info);
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int
|
|
Packit |
5e46da |
_parse_stream(BITSTREAM *bits, MPLS_STREAM *s)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int len;
|
|
Packit |
5e46da |
int64_t pos;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!bs_is_align(bits, 0x07)) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_stream: Stream alignment error\n");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
len = bs_read(bits, 8);
|
|
Packit |
5e46da |
pos = bs_pos(bits) >> 3;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
s->stream_type = bs_read(bits, 8);
|
|
Packit |
5e46da |
switch (s->stream_type) {
|
|
Packit |
5e46da |
case 1:
|
|
Packit |
5e46da |
s->pid = bs_read(bits, 16);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
case 2:
|
|
Packit |
5e46da |
case 4:
|
|
Packit |
5e46da |
s->subpath_id = bs_read(bits, 8);
|
|
Packit |
5e46da |
s->subclip_id = bs_read(bits, 8);
|
|
Packit |
5e46da |
s->pid = bs_read(bits, 16);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
case 3:
|
|
Packit |
5e46da |
s->subpath_id = bs_read(bits, 8);
|
|
Packit |
5e46da |
s->pid = bs_read(bits, 16);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
default:
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "unrecognized stream type %02x\n", s->stream_type);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
};
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bs_seek_byte(bits, pos + len) < 0) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
len = bs_read(bits, 8);
|
|
Packit |
5e46da |
pos = bs_pos(bits) >> 3;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
s->lang[0] = '\0';
|
|
Packit |
5e46da |
s->coding_type = bs_read(bits, 8);
|
|
Packit |
5e46da |
switch (s->coding_type) {
|
|
Packit |
5e46da |
case 0x01:
|
|
Packit |
5e46da |
case 0x02:
|
|
Packit |
5e46da |
case 0xea:
|
|
Packit |
5e46da |
case 0x1b:
|
|
Packit |
5e46da |
case 0x24:
|
|
Packit |
5e46da |
s->format = bs_read(bits, 4);
|
|
Packit |
5e46da |
s->rate = bs_read(bits, 4);
|
|
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 |
s->format = bs_read(bits, 4);
|
|
Packit |
5e46da |
s->rate = bs_read(bits, 4);
|
|
Packit |
5e46da |
bs_read_string(bits, s->lang, 3);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
case 0x90:
|
|
Packit |
5e46da |
case 0x91:
|
|
Packit |
5e46da |
bs_read_string(bits, s->lang, 3);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
case 0x92:
|
|
Packit |
5e46da |
s->char_code = bs_read(bits, 8);
|
|
Packit |
5e46da |
bs_read_string(bits, s->lang, 3);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
default:
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "unrecognized coding type %02x\n", s->coding_type);
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
};
|
|
Packit |
5e46da |
s->lang[3] = '\0';
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bs_seek_byte(bits, pos + len) < 0) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int
|
|
Packit |
5e46da |
_parse_stn(BITSTREAM *bits, MPLS_STN *stn)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int len;
|
|
Packit |
5e46da |
int64_t pos;
|
|
Packit |
5e46da |
MPLS_STREAM *ss;
|
|
Packit |
5e46da |
int ii,jj;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!bs_is_align(bits, 0x07)) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_stream: Stream alignment error\n");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
// Skip STN len
|
|
Packit |
5e46da |
len = bs_read(bits, 16);
|
|
Packit |
5e46da |
pos = bs_pos(bits) >> 3;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Skip 2 reserved bytes
|
|
Packit |
5e46da |
bs_skip(bits, 16);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
stn->num_video = bs_read(bits, 8);
|
|
Packit |
5e46da |
stn->num_audio = bs_read(bits, 8);
|
|
Packit |
5e46da |
stn->num_pg = bs_read(bits, 8);
|
|
Packit |
5e46da |
stn->num_ig = bs_read(bits, 8);
|
|
Packit |
5e46da |
stn->num_secondary_audio = bs_read(bits, 8);
|
|
Packit |
5e46da |
stn->num_secondary_video = bs_read(bits, 8);
|
|
Packit |
5e46da |
stn->num_pip_pg = bs_read(bits, 8);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// 5 reserve bytes
|
|
Packit |
5e46da |
bs_skip(bits, 5 * 8);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Primary Video Streams
|
|
Packit |
5e46da |
ss = NULL;
|
|
Packit |
5e46da |
if (stn->num_video) {
|
|
Packit |
5e46da |
ss = calloc(stn->num_video, sizeof(MPLS_STREAM));
|
|
Packit |
5e46da |
if (!ss) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
for (ii = 0; ii < stn->num_video; ii++) {
|
|
Packit |
5e46da |
if (!_parse_stream(bits, &ss[ii])) {
|
|
Packit |
5e46da |
X_FREE(ss);
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "error parsing video entry\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
stn->video = ss;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Primary Audio Streams
|
|
Packit |
5e46da |
ss = NULL;
|
|
Packit |
5e46da |
if (stn->num_audio) {
|
|
Packit |
5e46da |
ss = calloc(stn->num_audio, sizeof(MPLS_STREAM));
|
|
Packit |
5e46da |
if (!ss) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
for (ii = 0; ii < stn->num_audio; ii++) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!_parse_stream(bits, &ss[ii])) {
|
|
Packit |
5e46da |
X_FREE(ss);
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "error parsing audio entry\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
stn->audio = ss;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Presentation Graphic Streams
|
|
Packit |
5e46da |
ss = NULL;
|
|
Packit |
5e46da |
if (stn->num_pg || stn->num_pip_pg) {
|
|
Packit |
5e46da |
ss = calloc(stn->num_pg + stn->num_pip_pg, sizeof(MPLS_STREAM));
|
|
Packit |
5e46da |
if (!ss) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
for (ii = 0; ii < (stn->num_pg + stn->num_pip_pg); ii++) {
|
|
Packit |
5e46da |
if (!_parse_stream(bits, &ss[ii])) {
|
|
Packit |
5e46da |
X_FREE(ss);
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "error parsing pg/pip-pg entry\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
stn->pg = ss;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Interactive Graphic Streams
|
|
Packit |
5e46da |
ss = NULL;
|
|
Packit |
5e46da |
if (stn->num_ig) {
|
|
Packit |
5e46da |
ss = calloc(stn->num_ig, sizeof(MPLS_STREAM));
|
|
Packit |
5e46da |
if (!ss) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
for (ii = 0; ii < stn->num_ig; ii++) {
|
|
Packit |
5e46da |
if (!_parse_stream(bits, &ss[ii])) {
|
|
Packit |
5e46da |
X_FREE(ss);
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "error parsing ig entry\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
stn->ig = ss;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Secondary Audio Streams
|
|
Packit |
5e46da |
if (stn->num_secondary_audio) {
|
|
Packit |
5e46da |
ss = calloc(stn->num_secondary_audio, sizeof(MPLS_STREAM));
|
|
Packit |
5e46da |
if (!ss) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
stn->secondary_audio = ss;
|
|
Packit |
5e46da |
for (ii = 0; ii < stn->num_secondary_audio; ii++) {
|
|
Packit |
5e46da |
if (!_parse_stream(bits, &ss[ii])) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "error parsing secondary audio entry\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
// Read Secondary Audio Extra Attributes
|
|
Packit |
5e46da |
ss[ii].sa_num_primary_audio_ref = bs_read(bits, 8);
|
|
Packit |
5e46da |
bs_skip(bits, 8);
|
|
Packit |
5e46da |
if (ss[ii].sa_num_primary_audio_ref) {
|
|
Packit |
5e46da |
ss[ii].sa_primary_audio_ref = calloc(ss[ii].sa_num_primary_audio_ref, sizeof(uint8_t));
|
|
Packit |
5e46da |
if (!ss[ii].sa_primary_audio_ref) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
for (jj = 0; jj < ss[ii].sa_num_primary_audio_ref; jj++) {
|
|
Packit |
5e46da |
ss[ii].sa_primary_audio_ref[jj] = bs_read(bits, 8);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (ss[ii].sa_num_primary_audio_ref % 2) {
|
|
Packit |
5e46da |
bs_skip(bits, 8);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Secondary Video Streams
|
|
Packit |
5e46da |
if (stn->num_secondary_video) {
|
|
Packit |
5e46da |
ss = calloc(stn->num_secondary_video, sizeof(MPLS_STREAM));
|
|
Packit |
5e46da |
if (!ss) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
stn->secondary_video = ss;
|
|
Packit |
5e46da |
for (ii = 0; ii < stn->num_secondary_video; ii++) {
|
|
Packit |
5e46da |
if (!_parse_stream(bits, &ss[ii])) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "error parsing secondary video entry\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
// Read Secondary Video Extra Attributes
|
|
Packit |
5e46da |
ss[ii].sv_num_secondary_audio_ref = bs_read(bits, 8);
|
|
Packit |
5e46da |
bs_skip(bits, 8);
|
|
Packit |
5e46da |
if (ss[ii].sv_num_secondary_audio_ref) {
|
|
Packit |
5e46da |
ss[ii].sv_secondary_audio_ref = calloc(ss[ii].sv_num_secondary_audio_ref, sizeof(uint8_t));
|
|
Packit |
5e46da |
if (!ss[ii].sv_secondary_audio_ref) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
for (jj = 0; jj < ss[ii].sv_num_secondary_audio_ref; jj++) {
|
|
Packit |
5e46da |
ss[ii].sv_secondary_audio_ref[jj] = bs_read(bits, 8);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (ss[ii].sv_num_secondary_audio_ref % 2) {
|
|
Packit |
5e46da |
bs_skip(bits, 8);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
ss[ii].sv_num_pip_pg_ref = bs_read(bits, 8);
|
|
Packit |
5e46da |
bs_skip(bits, 8);
|
|
Packit |
5e46da |
if (ss[ii].sv_num_pip_pg_ref) {
|
|
Packit |
5e46da |
ss[ii].sv_pip_pg_ref = calloc(ss[ii].sv_num_pip_pg_ref, sizeof(uint8_t));
|
|
Packit |
5e46da |
if (!ss[ii].sv_pip_pg_ref) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
for (jj = 0; jj < ss[ii].sv_num_pip_pg_ref; jj++) {
|
|
Packit |
5e46da |
ss[ii].sv_pip_pg_ref[jj] = bs_read(bits, 8);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (ss[ii].sv_num_pip_pg_ref % 2) {
|
|
Packit |
5e46da |
bs_skip(bits, 8);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bs_seek_byte(bits, pos + len) < 0) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void
|
|
Packit |
5e46da |
_clean_stn(MPLS_STN *stn)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if(stn->secondary_audio) {
|
|
Packit |
5e46da |
for (ii = 0; ii < stn->num_secondary_audio; ii++) {
|
|
Packit |
5e46da |
X_FREE(stn->secondary_audio[ii].sa_primary_audio_ref);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if(stn->secondary_video) {
|
|
Packit |
5e46da |
for (ii = 0; ii < stn->num_secondary_video; ii++) {
|
|
Packit |
5e46da |
X_FREE(stn->secondary_video[ii].sv_secondary_audio_ref);
|
|
Packit |
5e46da |
X_FREE(stn->secondary_video[ii].sv_pip_pg_ref);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
X_FREE(stn->video);
|
|
Packit |
5e46da |
X_FREE(stn->audio);
|
|
Packit |
5e46da |
X_FREE(stn->pg);
|
|
Packit |
5e46da |
X_FREE(stn->ig);
|
|
Packit |
5e46da |
X_FREE(stn->secondary_audio);
|
|
Packit |
5e46da |
X_FREE(stn->secondary_video);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int
|
|
Packit |
5e46da |
_parse_playitem(BITSTREAM *bits, MPLS_PI *pi)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int len, ii;
|
|
Packit |
5e46da |
int64_t pos;
|
|
Packit |
5e46da |
char clip_id[6], codec_id[5];
|
|
Packit |
5e46da |
uint8_t stc_id;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!bs_is_align(bits, 0x07)) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_playitem: Stream alignment error\n");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// PlayItem Length
|
|
Packit |
5e46da |
len = bs_read(bits, 16);
|
|
Packit |
5e46da |
pos = bs_pos(bits) >> 3;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (len < 18) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_playitem: invalid length %d\n", len);
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (bs_avail(bits)/8 < len) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_playitem: unexpected EOF\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Primary Clip identifer
|
|
Packit |
5e46da |
bs_read_string(bits, clip_id, 5);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bs_read_string(bits, codec_id, 4);
|
|
Packit |
5e46da |
if (memcmp(codec_id, "M2TS", 4) != 0) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "Incorrect CodecIdentifier (%s)\n", codec_id);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Skip reserved 11 bits
|
|
Packit |
5e46da |
bs_skip(bits, 11);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
pi->is_multi_angle = bs_read(bits, 1);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
pi->connection_condition = bs_read(bits, 4);
|
|
Packit |
5e46da |
if (pi->connection_condition != 0x01 &&
|
|
Packit |
5e46da |
pi->connection_condition != 0x05 &&
|
|
Packit |
5e46da |
pi->connection_condition != 0x06) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "Unexpected connection condition %02x\n",
|
|
Packit |
5e46da |
pi->connection_condition);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
stc_id = bs_read(bits, 8);
|
|
Packit |
5e46da |
pi->in_time = bs_read(bits, 32);
|
|
Packit |
5e46da |
pi->out_time = bs_read(bits, 32);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_parse_uo(bits, &pi->uo_mask);
|
|
Packit |
5e46da |
pi->random_access_flag = bs_read(bits, 1);
|
|
Packit |
5e46da |
bs_skip(bits, 7);
|
|
Packit |
5e46da |
pi->still_mode = bs_read(bits, 8);
|
|
Packit |
5e46da |
if (pi->still_mode == 0x01) {
|
|
Packit |
5e46da |
pi->still_time = bs_read(bits, 16);
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
bs_skip(bits, 16);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
pi->angle_count = 1;
|
|
Packit |
5e46da |
if (pi->is_multi_angle) {
|
|
Packit |
5e46da |
pi->angle_count = bs_read(bits, 8);
|
|
Packit |
5e46da |
if (pi->angle_count < 1) {
|
|
Packit |
5e46da |
pi->angle_count = 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
bs_skip(bits, 6);
|
|
Packit |
5e46da |
pi->is_different_audio = bs_read(bits, 1);
|
|
Packit |
5e46da |
pi->is_seamless_angle = bs_read(bits, 1);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
pi->clip = calloc(pi->angle_count, sizeof(MPLS_CLIP));
|
|
Packit |
5e46da |
if (!pi->clip) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
strcpy(pi->clip[0].clip_id, clip_id);
|
|
Packit |
5e46da |
strcpy(pi->clip[0].codec_id, codec_id);
|
|
Packit |
5e46da |
pi->clip[0].stc_id = stc_id;
|
|
Packit |
5e46da |
for (ii = 1; ii < pi->angle_count; ii++) {
|
|
Packit |
5e46da |
bs_read_string(bits, pi->clip[ii].clip_id, 5);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bs_read_string(bits, pi->clip[ii].codec_id, 4);
|
|
Packit |
5e46da |
if (memcmp(pi->clip[ii].codec_id, "M2TS", 4) != 0) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "Incorrect CodecIdentifier (%s)\n", pi->clip[ii].codec_id);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
pi->clip[ii].stc_id = bs_read(bits, 8);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (!_parse_stn(bits, &pi->stn)) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Seek past any unused items
|
|
Packit |
5e46da |
if (bs_seek_byte(bits, pos + len) < 0) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void
|
|
Packit |
5e46da |
_clean_playitem(MPLS_PI *pi)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
X_FREE(pi->clip);
|
|
Packit |
5e46da |
_clean_stn(&pi->stn);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int
|
|
Packit |
5e46da |
_parse_subplayitem(BITSTREAM *bits, MPLS_SUB_PI *spi)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int len, ii;
|
|
Packit |
5e46da |
int64_t pos;
|
|
Packit |
5e46da |
char clip_id[6], codec_id[5];
|
|
Packit |
5e46da |
uint8_t stc_id;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!bs_is_align(bits, 0x07)) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_subplayitem: alignment error\n");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// PlayItem Length
|
|
Packit |
5e46da |
len = bs_read(bits, 16);
|
|
Packit |
5e46da |
pos = bs_pos(bits) >> 3;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (len < 24) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_subplayitem: invalid length %d\n", len);
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bs_avail(bits)/8 < len) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_subplayitem: unexpected EOF\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Primary Clip identifer
|
|
Packit |
5e46da |
bs_read_string(bits, clip_id, 5);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bs_read_string(bits, codec_id, 4);
|
|
Packit |
5e46da |
if (memcmp(codec_id, "M2TS", 4) != 0) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "Incorrect CodecIdentifier (%s)\n", codec_id);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bs_skip(bits, 27);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
spi->connection_condition = bs_read(bits, 4);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (spi->connection_condition != 0x01 &&
|
|
Packit |
5e46da |
spi->connection_condition != 0x05 &&
|
|
Packit |
5e46da |
spi->connection_condition != 0x06) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "Unexpected connection condition %02x\n",
|
|
Packit |
5e46da |
spi->connection_condition);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
spi->is_multi_clip = bs_read(bits, 1);
|
|
Packit |
5e46da |
stc_id = bs_read(bits, 8);
|
|
Packit |
5e46da |
spi->in_time = bs_read(bits, 32);
|
|
Packit |
5e46da |
spi->out_time = bs_read(bits, 32);
|
|
Packit |
5e46da |
spi->sync_play_item_id = bs_read(bits, 16);
|
|
Packit |
5e46da |
spi->sync_pts = bs_read(bits, 32);
|
|
Packit |
5e46da |
spi->clip_count = 1;
|
|
Packit |
5e46da |
if (spi->is_multi_clip) {
|
|
Packit |
5e46da |
spi->clip_count = bs_read(bits, 8);
|
|
Packit |
5e46da |
if (spi->clip_count < 1) {
|
|
Packit |
5e46da |
spi->clip_count = 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
spi->clip = calloc(spi->clip_count, sizeof(MPLS_CLIP));
|
|
Packit |
5e46da |
if (!spi->clip) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
strcpy(spi->clip[0].clip_id, clip_id);
|
|
Packit |
5e46da |
strcpy(spi->clip[0].codec_id, codec_id);
|
|
Packit |
5e46da |
spi->clip[0].stc_id = stc_id;
|
|
Packit |
5e46da |
for (ii = 1; ii < spi->clip_count; ii++) {
|
|
Packit |
5e46da |
// Primary Clip identifer
|
|
Packit |
5e46da |
bs_read_string(bits, spi->clip[ii].clip_id, 5);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bs_read_string(bits, spi->clip[ii].codec_id, 4);
|
|
Packit |
5e46da |
if (memcmp(spi->clip[ii].codec_id, "M2TS", 4) != 0) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "Incorrect CodecIdentifier (%s)\n", spi->clip[ii].codec_id);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
spi->clip[ii].stc_id = bs_read(bits, 8);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Seek to end of subpath
|
|
Packit |
5e46da |
if (bs_seek_byte(bits, pos + len) < 0) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void
|
|
Packit |
5e46da |
_clean_subplayitem(MPLS_SUB_PI *spi)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
X_FREE(spi->clip);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int
|
|
Packit |
5e46da |
_parse_subpath(BITSTREAM *bits, MPLS_SUB *sp)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int len, ii;
|
|
Packit |
5e46da |
int64_t pos;
|
|
Packit |
5e46da |
MPLS_SUB_PI *spi = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!bs_is_align(bits, 0x07)) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_subpath: alignment error\n");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// PlayItem Length
|
|
Packit |
5e46da |
len = bs_read(bits, 32);
|
|
Packit |
5e46da |
pos = bs_pos(bits) >> 3;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bs_skip(bits, 8);
|
|
Packit |
5e46da |
sp->type = bs_read(bits, 8);
|
|
Packit |
5e46da |
bs_skip(bits, 15);
|
|
Packit |
5e46da |
sp->is_repeat = bs_read(bits, 1);
|
|
Packit |
5e46da |
bs_skip(bits, 8);
|
|
Packit |
5e46da |
sp->sub_playitem_count = bs_read(bits, 8);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (sp->sub_playitem_count) {
|
|
Packit |
5e46da |
spi = calloc(sp->sub_playitem_count, sizeof(MPLS_SUB_PI));
|
|
Packit |
5e46da |
if (!spi) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
sp->sub_play_item = spi;
|
|
Packit |
5e46da |
for (ii = 0; ii < sp->sub_playitem_count; ii++) {
|
|
Packit |
5e46da |
if (!_parse_subplayitem(bits, &spi[ii])) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "error parsing sub play item\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Seek to end of subpath
|
|
Packit |
5e46da |
if (bs_seek_byte(bits, pos + len) < 0) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void
|
|
Packit |
5e46da |
_clean_subpath(MPLS_SUB *sp)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int ii;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0; ii < sp->sub_playitem_count; ii++) {
|
|
Packit |
5e46da |
_clean_subplayitem(&sp->sub_play_item[ii]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE(sp->sub_play_item);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int
|
|
Packit |
5e46da |
_parse_playlistmark(BITSTREAM *bits, MPLS_PL *pl)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int64_t len;
|
|
Packit |
5e46da |
int ii;
|
|
Packit |
5e46da |
MPLS_PLM *plm = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bs_seek_byte(bits, pl->mark_pos) < 0) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// length field
|
|
Packit |
5e46da |
len = bs_read(bits, 32);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bs_avail(bits)/8 < len) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_playlistmark: unexpected EOF\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Then get the number of marks
|
|
Packit |
5e46da |
pl->mark_count = bs_read(bits, 16);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bs_avail(bits)/(8*14) < pl->mark_count) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_playlistmark: unexpected EOF\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
plm = calloc(pl->mark_count, sizeof(MPLS_PLM));
|
|
Packit |
5e46da |
if (pl->mark_count && !plm) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_CRIT, "out of memory\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0; ii < pl->mark_count; ii++) {
|
|
Packit |
5e46da |
bs_skip(bits, 8); /* reserved */
|
|
Packit |
5e46da |
plm[ii].mark_type = bs_read(bits, 8);
|
|
Packit |
5e46da |
plm[ii].play_item_ref = bs_read(bits, 16);
|
|
Packit |
5e46da |
plm[ii].time = bs_read(bits, 32);
|
|
Packit |
5e46da |
plm[ii].entry_es_pid = bs_read(bits, 16);
|
|
Packit |
5e46da |
plm[ii].duration = bs_read(bits, 32);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
pl->play_mark = plm;
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int
|
|
Packit |
5e46da |
_parse_playlist(BITSTREAM *bits, MPLS_PL *pl)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int64_t len;
|
|
Packit |
5e46da |
int ii;
|
|
Packit |
5e46da |
MPLS_PI *pi = NULL;
|
|
Packit |
5e46da |
MPLS_SUB *sub_path = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bs_seek_byte(bits, pl->list_pos) < 0) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// playlist length
|
|
Packit |
5e46da |
len = bs_read(bits, 32);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bs_avail(bits) < len * 8) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_playlist: unexpected end of file\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Skip reserved bytes
|
|
Packit |
5e46da |
bs_skip(bits, 16);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
pl->list_count = bs_read(bits, 16);
|
|
Packit |
5e46da |
pl->sub_count = bs_read(bits, 16);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (pl->list_count) {
|
|
Packit |
5e46da |
pi = calloc(pl->list_count, sizeof(MPLS_PI));
|
|
Packit |
5e46da |
if (!pi) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
pl->play_item = pi;
|
|
Packit |
5e46da |
for (ii = 0; ii < pl->list_count; ii++) {
|
|
Packit |
5e46da |
if (!_parse_playitem(bits, &pi[ii])) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "error parsing play list item\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (pl->sub_count) {
|
|
Packit |
5e46da |
sub_path = calloc(pl->sub_count, sizeof(MPLS_SUB));
|
|
Packit |
5e46da |
if (!sub_path) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
pl->sub_path = sub_path;
|
|
Packit |
5e46da |
for (ii = 0; ii < pl->sub_count; ii++)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (!_parse_subpath(bits, &sub_path[ii]))
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "error parsing subpath\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _clean_pip_data(MPLS_PIP_METADATA *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
X_FREE(p->data);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void
|
|
Packit |
5e46da |
_clean_playlist(MPLS_PL *pl)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int ii;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (pl->play_item != NULL) {
|
|
Packit |
5e46da |
for (ii = 0; ii < pl->list_count; ii++) {
|
|
Packit |
5e46da |
_clean_playitem(&pl->play_item[ii]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE(pl->play_item);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (pl->sub_path != NULL) {
|
|
Packit |
5e46da |
for (ii = 0; ii < pl->sub_count; ii++) {
|
|
Packit |
5e46da |
_clean_subpath(&pl->sub_path[ii]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE(pl->sub_path);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (pl->ext_sub_path != NULL) {
|
|
Packit |
5e46da |
for (ii = 0; ii < pl->ext_sub_count; ii++) {
|
|
Packit |
5e46da |
_clean_subpath(&pl->ext_sub_path[ii]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE(pl->ext_sub_path);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (pl->ext_pip_data != NULL) {
|
|
Packit |
5e46da |
for (ii = 0; ii < pl->ext_pip_data_count; ii++) {
|
|
Packit |
5e46da |
_clean_pip_data(&pl->ext_pip_data[ii]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE(pl->ext_pip_data);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
X_FREE(pl->play_mark);
|
|
Packit |
5e46da |
X_FREE(pl);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
void
|
|
Packit |
5e46da |
mpls_free(MPLS_PL **pl)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (*pl) {
|
|
Packit |
5e46da |
_clean_playlist(*pl);
|
|
Packit |
5e46da |
*pl = NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int
|
|
Packit |
5e46da |
_parse_pip_data(BITSTREAM *bits, MPLS_PIP_METADATA *block)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
MPLS_PIP_DATA *data;
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
uint16_t entries = bs_read(bits, 16);
|
|
Packit |
5e46da |
if (entries < 1) {
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
data = calloc(entries, sizeof(MPLS_PIP_DATA));
|
|
Packit |
5e46da |
if (!data) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_CRIT, "out of memory\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0; ii < entries; ii++) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
data[ii].time = bs_read(bits, 32);
|
|
Packit |
5e46da |
data[ii].xpos = bs_read(bits, 12);
|
|
Packit |
5e46da |
data[ii].ypos = bs_read(bits, 12);
|
|
Packit |
5e46da |
data[ii].scale_factor = bs_read(bits, 4);
|
|
Packit |
5e46da |
bs_skip(bits, 4);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
block->data_count = entries;
|
|
Packit |
5e46da |
block->data = data;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int
|
|
Packit |
5e46da |
_parse_pip_metadata_block(BITSTREAM *bits, uint32_t start_address, MPLS_PIP_METADATA *data)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
uint32_t data_address;
|
|
Packit |
5e46da |
int result;
|
|
Packit |
5e46da |
int64_t pos;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
data->clip_ref = bs_read(bits, 16);
|
|
Packit |
5e46da |
data->secondary_video_ref = bs_read(bits, 8);
|
|
Packit |
5e46da |
bs_skip(bits, 8);
|
|
Packit |
5e46da |
data->timeline_type = bs_read(bits, 4);
|
|
Packit |
5e46da |
data->luma_key_flag = bs_read(bits, 1);
|
|
Packit |
5e46da |
data->trick_play_flag = bs_read(bits, 1);
|
|
Packit |
5e46da |
bs_skip(bits, 10);
|
|
Packit |
5e46da |
if (data->luma_key_flag) {
|
|
Packit |
5e46da |
bs_skip(bits, 8);
|
|
Packit |
5e46da |
data->upper_limit_luma_key = bs_read(bits, 8);
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
bs_skip(bits, 16);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
bs_skip(bits, 16);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
data_address = bs_read(bits, 32);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
pos = bs_pos(bits) / 8;
|
|
Packit |
5e46da |
if (bs_seek_byte(bits, start_address + data_address) < 0) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
result = _parse_pip_data(bits, data);
|
|
Packit |
5e46da |
if (bs_seek_byte(bits, pos) < 0) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return result;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int
|
|
Packit |
5e46da |
_parse_pip_metadata_extension(BITSTREAM *bits, MPLS_PL *pl)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
MPLS_PIP_METADATA *data;
|
|
Packit |
5e46da |
int ii;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
uint32_t start_address = (uint32_t)bs_pos(bits) / 8;
|
|
Packit |
5e46da |
uint32_t len = bs_read(bits, 32);
|
|
Packit |
5e46da |
int entries = bs_read(bits, 16);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (len < 1 || entries < 1) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
data = calloc(entries, sizeof(MPLS_PIP_METADATA));
|
|
Packit |
5e46da |
if (!data) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_CRIT, "out of memory\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0; ii < entries; ii++) {
|
|
Packit |
5e46da |
if (!_parse_pip_metadata_block(bits, start_address, &data[ii])) {
|
|
Packit |
5e46da |
goto error;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
pl->ext_pip_data_count = entries;
|
|
Packit |
5e46da |
pl->ext_pip_data = data;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
error:
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "error parsing pip metadata extension\n");
|
|
Packit |
5e46da |
for (ii = 0; ii < entries; ii++) {
|
|
Packit |
5e46da |
_clean_pip_data(&data[ii]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE(data);
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int
|
|
Packit |
5e46da |
_parse_subpath_extension(BITSTREAM *bits, MPLS_PL *pl)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
MPLS_SUB *sub_path;
|
|
Packit |
5e46da |
int ii;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
uint32_t len = bs_read(bits, 32);
|
|
Packit |
5e46da |
int sub_count = bs_read(bits, 16);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (len < 1 || sub_count < 1) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
sub_path = calloc(sub_count, sizeof(MPLS_SUB));
|
|
Packit |
5e46da |
if (!sub_path) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_CRIT, "out of memory\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0; ii < sub_count; ii++) {
|
|
Packit |
5e46da |
if (!_parse_subpath(bits, &sub_path[ii])) {
|
|
Packit |
5e46da |
goto error;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
pl->ext_sub_path = sub_path;
|
|
Packit |
5e46da |
pl->ext_sub_count = sub_count;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
error:
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "error parsing extension subpath\n");
|
|
Packit |
5e46da |
for (ii = 0; ii < sub_count; ii++) {
|
|
Packit |
5e46da |
_clean_subpath(&sub_path[ii]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE(sub_path);
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int
|
|
Packit |
5e46da |
_parse_mpls_extension(BITSTREAM *bits, int id1, int id2, void *handle)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
MPLS_PL *pl = (MPLS_PL*)handle;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (id1 == 1) {
|
|
Packit |
5e46da |
if (id2 == 1) {
|
|
Packit |
5e46da |
// PiP metadata extension
|
|
Packit |
5e46da |
return _parse_pip_metadata_extension(bits, pl);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (id1 == 2) {
|
|
Packit |
5e46da |
if (id2 == 1) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (id2 == 2) {
|
|
Packit |
5e46da |
// SubPath entries extension
|
|
Packit |
5e46da |
return _parse_subpath_extension(bits, pl);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "_parse_mpls_extension(): unhandled extension %d.%d\n", id1, id2);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static MPLS_PL*
|
|
Packit |
5e46da |
_mpls_parse(BD_FILE_H *fp)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
BITSTREAM bits;
|
|
Packit |
5e46da |
MPLS_PL *pl = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bs_init(&bits, fp) < 0) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV, "?????.mpls: read error\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
pl = calloc(1, sizeof(MPLS_PL));
|
|
Packit |
5e46da |
if (pl == 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, pl)) {
|
|
Packit |
5e46da |
_clean_playlist(pl);
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (!_parse_playlist(&bits, pl)) {
|
|
Packit |
5e46da |
_clean_playlist(pl);
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (!_parse_playlistmark(&bits, pl)) {
|
|
Packit |
5e46da |
_clean_playlist(pl);
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (pl->ext_pos > 0) {
|
|
Packit |
5e46da |
bdmv_parse_extension_data(&bits,
|
|
Packit |
5e46da |
pl->ext_pos,
|
|
Packit |
5e46da |
_parse_mpls_extension,
|
|
Packit |
5e46da |
pl);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return pl;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
MPLS_PL*
|
|
Packit |
5e46da |
mpls_parse(const char *path)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
MPLS_PL *pl;
|
|
Packit |
5e46da |
BD_FILE_H *fp;
|
|
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 |
pl = _mpls_parse(fp);
|
|
Packit |
5e46da |
file_close(fp);
|
|
Packit |
5e46da |
return pl;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static MPLS_PL*
|
|
Packit |
5e46da |
_mpls_get(BD_DISC *disc, const char *dir, const char *file)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
MPLS_PL *pl;
|
|
Packit |
5e46da |
BD_FILE_H *fp;
|
|
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 |
pl = _mpls_parse(fp);
|
|
Packit |
5e46da |
file_close(fp);
|
|
Packit |
5e46da |
return pl;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
MPLS_PL*
|
|
Packit |
5e46da |
mpls_get(BD_DISC *disc, const char *file)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
MPLS_PL *pl;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
pl = _mpls_get(disc, "BDMV" DIR_SEP "PLAYLIST", file);
|
|
Packit |
5e46da |
if (pl) {
|
|
Packit |
5e46da |
return pl;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* if failed, try backup file */
|
|
Packit |
5e46da |
pl = _mpls_get(disc, "BDMV" DIR_SEP "BACKUP" DIR_SEP "PLAYLIST", file);
|
|
Packit |
5e46da |
return pl;
|
|
Packit |
5e46da |
}
|