|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* This file is part of libbluray
|
|
Packit |
5e46da |
* Copyright (C) 2009-2010 John Stebbins
|
|
Packit |
5e46da |
* Copyright (C) 2010-2016 Petri Hintukainen
|
|
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 "navigation.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "clpi_parse.h"
|
|
Packit |
5e46da |
#include "mpls_parse.h"
|
|
Packit |
5e46da |
#include "bdparse.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "disc/disc.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "util/macro.h"
|
|
Packit |
5e46da |
#include "util/logging.h"
|
|
Packit |
5e46da |
#include "util/strutl.h"
|
|
Packit |
5e46da |
#include "file/file.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include <stdlib.h>
|
|
Packit |
5e46da |
#include <string.h>
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* Utils
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static uint32_t
|
|
Packit |
5e46da |
_pl_duration(MPLS_PL *pl)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
uint32_t duration = 0;
|
|
Packit |
5e46da |
MPLS_PI *pi;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0; ii < pl->list_count; ii++) {
|
|
Packit |
5e46da |
pi = &pl->play_item[ii];
|
|
Packit |
5e46da |
duration += pi->out_time - pi->in_time;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
return duration;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static uint32_t
|
|
Packit |
5e46da |
_pl_chapter_count(MPLS_PL *pl)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned ii, chapters = 0;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Count the number of "entry" marks (skipping "link" marks)
|
|
Packit |
5e46da |
// This is the the number of chapters
|
|
Packit |
5e46da |
for (ii = 0; ii < pl->mark_count; ii++) {
|
|
Packit |
5e46da |
if (pl->play_mark[ii].mark_type == BD_MARK_ENTRY) {
|
|
Packit |
5e46da |
chapters++;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
return chapters;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* Check if two playlists are the same
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _stream_cmp(MPLS_STREAM *a, MPLS_STREAM *b)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (a->stream_type == b->stream_type &&
|
|
Packit |
5e46da |
a->coding_type == b->coding_type &&
|
|
Packit |
5e46da |
a->pid == b->pid &&
|
|
Packit |
5e46da |
a->subpath_id == b->subpath_id &&
|
|
Packit |
5e46da |
a->subclip_id == b->subclip_id &&
|
|
Packit |
5e46da |
a->format == b->format &&
|
|
Packit |
5e46da |
a->rate == b->rate &&
|
|
Packit |
5e46da |
a->char_code == b->char_code &&
|
|
Packit |
5e46da |
memcmp(a->lang, b->lang, 4) == 0) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _streams_cmp(MPLS_STREAM *s1, MPLS_STREAM *s2, unsigned count)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
for (ii = 0; ii < count; ii++) {
|
|
Packit |
5e46da |
if (_stream_cmp(&s1[ii], &s2[ii])) {
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _pi_cmp(MPLS_PI *pi1, MPLS_PI *pi2)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (memcmp(pi1->clip[0].clip_id, pi2->clip[0].clip_id, 5) != 0 ||
|
|
Packit |
5e46da |
pi1->in_time != pi2->in_time ||
|
|
Packit |
5e46da |
pi1->out_time != pi2->out_time) {
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (pi1->stn.num_video != pi2->stn.num_video ||
|
|
Packit |
5e46da |
pi1->stn.num_audio != pi2->stn.num_audio ||
|
|
Packit |
5e46da |
pi1->stn.num_pg != pi2->stn.num_pg ||
|
|
Packit |
5e46da |
pi1->stn.num_ig != pi2->stn.num_ig ||
|
|
Packit |
5e46da |
pi1->stn.num_secondary_audio != pi2->stn.num_secondary_audio ||
|
|
Packit |
5e46da |
pi1->stn.num_secondary_video != pi2->stn.num_secondary_video) {
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (_streams_cmp(pi1->stn.video, pi2->stn.video, pi1->stn.num_video) ||
|
|
Packit |
5e46da |
_streams_cmp(pi1->stn.audio, pi2->stn.audio, pi1->stn.num_audio) ||
|
|
Packit |
5e46da |
_streams_cmp(pi1->stn.pg, pi2->stn.pg, pi1->stn.num_pg) ||
|
|
Packit |
5e46da |
_streams_cmp(pi1->stn.ig, pi2->stn.ig, pi1->stn.num_ig) ||
|
|
Packit |
5e46da |
_streams_cmp(pi1->stn.secondary_audio, pi2->stn.secondary_audio, pi1->stn.num_secondary_audio) ||
|
|
Packit |
5e46da |
_streams_cmp(pi1->stn.secondary_video, pi2->stn.secondary_video, pi1->stn.num_secondary_video)) {
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _pm_cmp(MPLS_PLM *pm1, MPLS_PLM *pm2)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (pm1->mark_type == pm2->mark_type &&
|
|
Packit |
5e46da |
pm1->play_item_ref == pm2->play_item_ref &&
|
|
Packit |
5e46da |
pm1->time == pm2->time &&
|
|
Packit |
5e46da |
pm1->entry_es_pid == pm2->entry_es_pid &&
|
|
Packit |
5e46da |
pm1->duration == pm2->duration ) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _pl_cmp(MPLS_PL *pl1, MPLS_PL *pl2)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (pl1->list_count != pl2->list_count) {
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (pl1->mark_count != pl2->mark_count) {
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (pl1->sub_count != pl2->sub_count) {
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (pl1->ext_sub_count != pl2->ext_sub_count) {
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0; ii < pl1->mark_count; ii++) {
|
|
Packit |
5e46da |
if (_pm_cmp(&pl1->play_mark[ii], &pl2->play_mark[ii])) {
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
for (ii = 0; ii < pl1->list_count; ii++) {
|
|
Packit |
5e46da |
if (_pi_cmp(&pl1->play_item[ii], &pl2->play_item[ii])) {
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* Playlist filtering
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* return 0 if duplicate playlist */
|
|
Packit |
5e46da |
static int _filter_dup(MPLS_PL *pl_list[], unsigned count, MPLS_PL *pl)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0; ii < count; ii++) {
|
|
Packit |
5e46da |
if (!_pl_cmp(pl, pl_list[ii])) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static unsigned int
|
|
Packit |
5e46da |
_find_repeats(MPLS_PL *pl, const char *m2ts, uint32_t in_time, uint32_t out_time)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned ii, count = 0;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0; ii < pl->list_count; ii++) {
|
|
Packit |
5e46da |
MPLS_PI *pi;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
pi = &pl->play_item[ii];
|
|
Packit |
5e46da |
// Ignore titles with repeated segments
|
|
Packit |
5e46da |
if (strcmp(pi->clip[0].clip_id, m2ts) == 0 &&
|
|
Packit |
5e46da |
pi->in_time == in_time &&
|
|
Packit |
5e46da |
pi->out_time == out_time) {
|
|
Packit |
5e46da |
count++;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
return count;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int
|
|
Packit |
5e46da |
_filter_repeats(MPLS_PL *pl, unsigned repeats)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0; ii < pl->list_count; ii++) {
|
|
Packit |
5e46da |
MPLS_PI *pi;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
pi = &pl->play_item[ii];
|
|
Packit |
5e46da |
// Ignore titles with repeated segments
|
|
Packit |
5e46da |
if (_find_repeats(pl, pi->clip[0].clip_id, pi->in_time, pi->out_time) > repeats) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* find main movie playlist
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#define DBG_MAIN_PL DBG_NAV
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _video_props(MPLS_STN *s, int *full_hd, int *mpeg12)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
*mpeg12 = 1;
|
|
Packit |
5e46da |
*full_hd = 0;
|
|
Packit |
5e46da |
for (ii = 0; ii < s->num_video; ii++) {
|
|
Packit |
5e46da |
if (s->video[ii].coding_type > 4) {
|
|
Packit |
5e46da |
*mpeg12 = 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (s->video[ii].format == BD_VIDEO_FORMAT_1080I || s->video[ii].format == BD_VIDEO_FORMAT_1080P) {
|
|
Packit |
5e46da |
if (*full_hd < 1) {
|
|
Packit |
5e46da |
*full_hd = 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (s->video[ii].format == BD_VIDEO_FORMAT_2160P) {
|
|
Packit |
5e46da |
*full_hd = 2;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _audio_props(MPLS_STN *s, int *hd_audio)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
*hd_audio = 0;
|
|
Packit |
5e46da |
for (ii = 0; ii < s->num_audio; ii++) {
|
|
Packit |
5e46da |
if (s->audio[ii].format == BD_STREAM_TYPE_AUDIO_LPCM || s->audio[ii].format >= BD_STREAM_TYPE_AUDIO_TRUHD) {
|
|
Packit |
5e46da |
*hd_audio = 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _cmp_video_props(const MPLS_PL *p1, const MPLS_PL *p2)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
MPLS_STN *s1 = &p1->play_item[0].stn;
|
|
Packit |
5e46da |
MPLS_STN *s2 = &p2->play_item[0].stn;
|
|
Packit |
5e46da |
int fhd1, fhd2, mp12_1, mp12_2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_video_props(s1, &fhd1, &mp12_1);
|
|
Packit |
5e46da |
_video_props(s2, &fhd2, &mp12_2);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* prefer UHD over FHD over HD/SD */
|
|
Packit |
5e46da |
if (fhd1 != fhd2)
|
|
Packit |
5e46da |
return fhd2 - fhd1;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* prefer H.264/VC1 over MPEG1/2 */
|
|
Packit |
5e46da |
return mp12_2 - mp12_1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _cmp_audio_props(const MPLS_PL *p1, const MPLS_PL *p2)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
MPLS_STN *s1 = &p1->play_item[0].stn;
|
|
Packit |
5e46da |
MPLS_STN *s2 = &p2->play_item[0].stn;
|
|
Packit |
5e46da |
int hda1, hda2;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_audio_props(s1, &hda1);
|
|
Packit |
5e46da |
_audio_props(s2, &hda2);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* prefer HD audio formats */
|
|
Packit |
5e46da |
return hda2 - hda1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _pl_guess_main_title(MPLS_PL *p1, MPLS_PL *p2,
|
|
Packit |
5e46da |
const char *mpls_id1, const char *mpls_id2,
|
|
Packit |
5e46da |
const char *known_mpls_ids)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
uint32_t d1 = _pl_duration(p1);
|
|
Packit |
5e46da |
uint32_t d2 = _pl_duration(p2);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* if both longer than 30 min */
|
|
Packit |
5e46da |
if (d1 > 30*60*45000 && d2 > 30*60*45000) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* prefer many chapters over no chapters */
|
|
Packit |
5e46da |
int chap1 = _pl_chapter_count(p1);
|
|
Packit |
5e46da |
int chap2 = _pl_chapter_count(p2);
|
|
Packit |
5e46da |
int chap_diff = chap2 - chap1;
|
|
Packit |
5e46da |
if ((chap1 < 2 || chap2 < 2) && (chap_diff < -5 || chap_diff > 5)) {
|
|
Packit |
5e46da |
/* chapter count differs by more than 5 */
|
|
Packit |
5e46da |
BD_DEBUG(DBG_MAIN_PL, "main title (%s,%s): chapter count difference %d\n",
|
|
Packit |
5e46da |
mpls_id1, mpls_id2, chap_diff);
|
|
Packit |
5e46da |
return chap_diff;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* Check video: prefer HD over SD, H.264/VC1 over MPEG1/2 */
|
|
Packit |
5e46da |
int vid_diff = _cmp_video_props(p1, p2);
|
|
Packit |
5e46da |
if (vid_diff) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_MAIN_PL, "main title (%s,%s): video properties difference %d\n",
|
|
Packit |
5e46da |
mpls_id1, mpls_id2, vid_diff);
|
|
Packit |
5e46da |
return vid_diff;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* compare audio: prefer HD audio */
|
|
Packit |
5e46da |
int aud_diff = _cmp_audio_props(p1, p2);
|
|
Packit |
5e46da |
if (aud_diff) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_MAIN_PL, "main title (%s,%s): audio properties difference %d\n",
|
|
Packit |
5e46da |
mpls_id1, mpls_id2, aud_diff);
|
|
Packit |
5e46da |
return aud_diff;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* prefer "known good" playlists */
|
|
Packit |
5e46da |
if (known_mpls_ids) {
|
|
Packit |
5e46da |
int known1 = !!str_strcasestr(known_mpls_ids, mpls_id1);
|
|
Packit |
5e46da |
int known2 = !!str_strcasestr(known_mpls_ids, mpls_id2);
|
|
Packit |
5e46da |
int known_diff = known2 - known1;
|
|
Packit |
5e46da |
if (known_diff) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_MAIN_PL, "main title (%s,%s): prefer \"known\" playlist %s\n",
|
|
Packit |
5e46da |
mpls_id1, mpls_id2, known_diff < 0 ? mpls_id1 : mpls_id2);
|
|
Packit |
5e46da |
return known_diff;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* compare playlist duration, select longer playlist */
|
|
Packit |
5e46da |
if (d1 < d2) {
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (d1 > d2) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* title list
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
NAV_TITLE_LIST* nav_get_title_list(BD_DISC *disc, uint32_t flags, uint32_t min_title_length)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
BD_DIR_H *dir;
|
|
Packit |
5e46da |
BD_DIRENT ent;
|
|
Packit |
5e46da |
MPLS_PL **pl_list = NULL;
|
|
Packit |
5e46da |
MPLS_PL *pl = NULL;
|
|
Packit |
5e46da |
unsigned int ii, pl_list_size = 0;
|
|
Packit |
5e46da |
int res;
|
|
Packit |
5e46da |
NAV_TITLE_LIST *title_list = NULL;
|
|
Packit |
5e46da |
unsigned int title_info_alloc = 100;
|
|
Packit |
5e46da |
char *known_mpls_ids;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
dir = disc_open_dir(disc, "BDMV" DIR_SEP "PLAYLIST");
|
|
Packit |
5e46da |
if (dir == NULL) {
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
title_list = calloc(1, sizeof(NAV_TITLE_LIST));
|
|
Packit |
5e46da |
if (!title_list) {
|
|
Packit |
5e46da |
dir_close(dir);
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
title_list->title_info = calloc(title_info_alloc, sizeof(NAV_TITLE_INFO));
|
|
Packit |
5e46da |
if (!title_list->title_info) {
|
|
Packit |
5e46da |
X_FREE(title_list);
|
|
Packit |
5e46da |
dir_close(dir);
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
known_mpls_ids = disc_property_get(disc, DISC_PROPERTY_MAIN_FEATURE);
|
|
Packit |
5e46da |
if (!known_mpls_ids) {
|
|
Packit |
5e46da |
known_mpls_ids = disc_property_get(disc, DISC_PROPERTY_PLAYLISTS);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
ii = 0;
|
|
Packit |
5e46da |
for (res = dir_read(dir, &ent;; !res; res = dir_read(dir, &ent)) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (ent.d_name[0] == '.') {
|
|
Packit |
5e46da |
continue;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (ii >= pl_list_size) {
|
|
Packit |
5e46da |
MPLS_PL **tmp = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
pl_list_size += 100;
|
|
Packit |
5e46da |
tmp = realloc(pl_list, pl_list_size * sizeof(MPLS_PL*));
|
|
Packit |
5e46da |
if (tmp == NULL) {
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
pl_list = tmp;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
pl = mpls_get(disc, ent.d_name);
|
|
Packit |
5e46da |
if (pl != NULL) {
|
|
Packit |
5e46da |
if ((flags & TITLES_FILTER_DUP_TITLE) &&
|
|
Packit |
5e46da |
!_filter_dup(pl_list, ii, pl)) {
|
|
Packit |
5e46da |
mpls_free(&pl);
|
|
Packit |
5e46da |
continue;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if ((flags & TITLES_FILTER_DUP_CLIP) && !_filter_repeats(pl, 2)) {
|
|
Packit |
5e46da |
mpls_free(&pl);
|
|
Packit |
5e46da |
continue;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (min_title_length > 0 &&
|
|
Packit |
5e46da |
_pl_duration(pl) < min_title_length*45000) {
|
|
Packit |
5e46da |
mpls_free(&pl);
|
|
Packit |
5e46da |
continue;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (ii >= title_info_alloc) {
|
|
Packit |
5e46da |
NAV_TITLE_INFO *tmp = NULL;
|
|
Packit |
5e46da |
title_info_alloc += 100;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
tmp = realloc(title_list->title_info,
|
|
Packit |
5e46da |
title_info_alloc * sizeof(NAV_TITLE_INFO));
|
|
Packit |
5e46da |
if (tmp == NULL) {
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
title_list->title_info = tmp;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
pl_list[ii] = pl;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* main title guessing */
|
|
Packit |
5e46da |
if (_filter_dup(pl_list, ii, pl) &&
|
|
Packit |
5e46da |
_filter_repeats(pl, 2)) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (_pl_guess_main_title(pl_list[ii], pl_list[title_list->main_title_idx],
|
|
Packit |
5e46da |
ent.d_name,
|
|
Packit |
5e46da |
title_list->title_info[title_list->main_title_idx].name,
|
|
Packit |
5e46da |
known_mpls_ids) <= 0) {
|
|
Packit |
5e46da |
title_list->main_title_idx = ii;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
strncpy(title_list->title_info[ii].name, ent.d_name, 11);
|
|
Packit |
5e46da |
title_list->title_info[ii].name[10] = '\0';
|
|
Packit |
5e46da |
title_list->title_info[ii].ref = ii;
|
|
Packit |
5e46da |
title_list->title_info[ii].mpls_id = atoi(ent.d_name);
|
|
Packit |
5e46da |
title_list->title_info[ii].duration = _pl_duration(pl_list[ii]);
|
|
Packit |
5e46da |
ii++;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
dir_close(dir);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
title_list->count = ii;
|
|
Packit |
5e46da |
for (ii = 0; ii < title_list->count; ii++) {
|
|
Packit |
5e46da |
mpls_free(&pl_list[ii]);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE(known_mpls_ids);
|
|
Packit |
5e46da |
X_FREE(pl_list);
|
|
Packit |
5e46da |
return title_list;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
void nav_free_title_list(NAV_TITLE_LIST **title_list)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (*title_list) {
|
|
Packit |
5e46da |
X_FREE((*title_list)->title_info);
|
|
Packit |
5e46da |
X_FREE((*title_list));
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
uint8_t nav_lookup_aspect(NAV_CLIP *clip, int pid)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
CLPI_PROG *progs;
|
|
Packit |
5e46da |
int ii, jj;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (clip->cl == NULL) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
progs = clip->cl->program.progs;
|
|
Packit |
5e46da |
for (ii = 0; ii < clip->cl->program.num_prog; ii++) {
|
|
Packit |
5e46da |
CLPI_PROG_STREAM *ps = progs[ii].streams;
|
|
Packit |
5e46da |
for (jj = 0; jj < progs[ii].num_streams; jj++) {
|
|
Packit |
5e46da |
if (ps[jj].pid == pid)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
return ps[jj].aspect;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void
|
|
Packit |
5e46da |
_fill_mark(NAV_TITLE *title, NAV_MARK *mark, int entry)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
MPLS_PL *pl = title->pl;
|
|
Packit |
5e46da |
MPLS_PLM *plm;
|
|
Packit |
5e46da |
MPLS_PI *pi;
|
|
Packit |
5e46da |
NAV_CLIP *clip;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
plm = &pl->play_mark[entry];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
mark->mark_type = plm->mark_type;
|
|
Packit |
5e46da |
mark->clip_ref = plm->play_item_ref;
|
|
Packit |
5e46da |
clip = &title->clip_list.clip[mark->clip_ref];
|
|
Packit |
5e46da |
if (clip->cl != NULL && mark->clip_ref < title->pl->list_count) {
|
|
Packit |
5e46da |
mark->clip_pkt = clpi_lookup_spn(clip->cl, plm->time, 1,
|
|
Packit |
5e46da |
title->pl->play_item[mark->clip_ref].clip[title->angle].stc_id);
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
mark->clip_pkt = clip->start_pkt;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
mark->title_pkt = clip->title_pkt + mark->clip_pkt - clip->start_pkt;
|
|
Packit |
5e46da |
mark->clip_time = plm->time;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Calculate start of mark relative to beginning of playlist
|
|
Packit |
5e46da |
if (plm->play_item_ref < title->clip_list.count) {
|
|
Packit |
5e46da |
clip = &title->clip_list.clip[plm->play_item_ref];
|
|
Packit |
5e46da |
pi = &pl->play_item[plm->play_item_ref];
|
|
Packit |
5e46da |
mark->title_time = clip->title_time + plm->time - pi->in_time;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void
|
|
Packit |
5e46da |
_extrapolate_title(NAV_TITLE *title)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
uint32_t duration = 0;
|
|
Packit |
5e46da |
uint32_t pkt = 0;
|
|
Packit |
5e46da |
unsigned ii, jj;
|
|
Packit |
5e46da |
MPLS_PL *pl = title->pl;
|
|
Packit |
5e46da |
MPLS_PI *pi;
|
|
Packit |
5e46da |
MPLS_PLM *plm;
|
|
Packit |
5e46da |
NAV_MARK *mark, *prev = NULL;
|
|
Packit |
5e46da |
NAV_CLIP *clip;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0; ii < title->clip_list.count; ii++) {
|
|
Packit |
5e46da |
clip = &title->clip_list.clip[ii];
|
|
Packit |
5e46da |
pi = &pl->play_item[ii];
|
|
Packit |
5e46da |
if (pi->angle_count > title->angle_count) {
|
|
Packit |
5e46da |
title->angle_count = pi->angle_count;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
clip->title_time = duration;
|
|
Packit |
5e46da |
clip->duration = pi->out_time - pi->in_time;
|
|
Packit |
5e46da |
clip->title_pkt = pkt;
|
|
Packit |
5e46da |
duration += clip->duration;
|
|
Packit |
5e46da |
pkt += clip->end_pkt - clip->start_pkt;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
title->duration = duration;
|
|
Packit |
5e46da |
title->packets = pkt;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0, jj = 0; ii < pl->mark_count; ii++) {
|
|
Packit |
5e46da |
plm = &pl->play_mark[ii];
|
|
Packit |
5e46da |
if (plm->mark_type == BD_MARK_ENTRY) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
mark = &title->chap_list.mark[jj];
|
|
Packit |
5e46da |
_fill_mark(title, mark, ii);
|
|
Packit |
5e46da |
mark->number = jj;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Calculate duration of "entry" marks (chapters)
|
|
Packit |
5e46da |
if (plm->duration != 0) {
|
|
Packit |
5e46da |
mark->duration = plm->duration;
|
|
Packit |
5e46da |
} else if (prev != NULL) {
|
|
Packit |
5e46da |
if (prev->duration == 0) {
|
|
Packit |
5e46da |
prev->duration = mark->title_time - prev->title_time;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
prev = mark;
|
|
Packit |
5e46da |
jj++;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
mark = &title->mark_list.mark[ii];
|
|
Packit |
5e46da |
_fill_mark(title, mark, ii);
|
|
Packit |
5e46da |
mark->number = ii;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
title->chap_list.count = jj;
|
|
Packit |
5e46da |
if (prev != NULL && prev->duration == 0) {
|
|
Packit |
5e46da |
prev->duration = title->duration - prev->title_time;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void _fill_clip(NAV_TITLE *title,
|
|
Packit |
5e46da |
MPLS_CLIP *mpls_clip,
|
|
Packit |
5e46da |
uint8_t connection_condition, uint32_t in_time, uint32_t out_time,
|
|
Packit |
5e46da |
unsigned pi_angle_count,
|
|
Packit |
5e46da |
NAV_CLIP *clip,
|
|
Packit |
5e46da |
unsigned ref, uint32_t *pos, uint32_t *time)
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
char *file;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
clip->title = title;
|
|
Packit |
5e46da |
clip->ref = ref;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (title->angle >= pi_angle_count) {
|
|
Packit |
5e46da |
clip->angle = 0;
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
clip->angle = title->angle;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
strncpy(clip->name, mpls_clip[clip->angle].clip_id, 5);
|
|
Packit |
5e46da |
strncpy(&clip->name[5], ".m2ts", 6);
|
|
Packit |
5e46da |
clip->clip_id = atoi(mpls_clip[clip->angle].clip_id);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
clpi_free(&clip->cl);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
file = str_printf("%s.clpi", mpls_clip[clip->angle].clip_id);
|
|
Packit |
5e46da |
if (file) {
|
|
Packit |
5e46da |
clip->cl = clpi_get(title->disc, file);
|
|
Packit |
5e46da |
X_FREE(file);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (clip->cl == NULL) {
|
|
Packit |
5e46da |
clip->start_pkt = 0;
|
|
Packit |
5e46da |
clip->end_pkt = 0;
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
switch (connection_condition) {
|
|
Packit |
5e46da |
case 5:
|
|
Packit |
5e46da |
case 6:
|
|
Packit |
5e46da |
clip->start_pkt = 0;
|
|
Packit |
5e46da |
clip->connection = CONNECT_SEAMLESS;
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
default:
|
|
Packit |
5e46da |
if (ref) {
|
|
Packit |
5e46da |
clip->start_pkt = clpi_lookup_spn(clip->cl, in_time, 1,
|
|
Packit |
5e46da |
mpls_clip[clip->angle].stc_id);
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
clip->start_pkt = 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
clip->connection = CONNECT_NON_SEAMLESS;
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
clip->end_pkt = clpi_lookup_spn(clip->cl, out_time, 0,
|
|
Packit |
5e46da |
mpls_clip[clip->angle].stc_id);
|
|
Packit |
5e46da |
clip->in_time = in_time;
|
|
Packit |
5e46da |
clip->out_time = out_time;
|
|
Packit |
5e46da |
clip->title_pkt = *pos;
|
|
Packit |
5e46da |
*pos += clip->end_pkt - clip->start_pkt;
|
|
Packit |
5e46da |
clip->title_time = *time;
|
|
Packit |
5e46da |
*time += clip->out_time - clip->in_time;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
clip->stc_spn = clpi_find_stc_spn(clip->cl, mpls_clip[clip->angle].stc_id);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
NAV_TITLE* nav_title_open(BD_DISC *disc, const char *playlist, unsigned angle)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
NAV_TITLE *title = NULL;
|
|
Packit |
5e46da |
unsigned ii, ss;
|
|
Packit |
5e46da |
uint32_t pos = 0;
|
|
Packit |
5e46da |
uint32_t time = 0;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
title = calloc(1, sizeof(NAV_TITLE));
|
|
Packit |
5e46da |
if (title == NULL) {
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
title->disc = disc;
|
|
Packit |
5e46da |
strncpy(title->name, playlist, 11);
|
|
Packit |
5e46da |
title->name[10] = '\0';
|
|
Packit |
5e46da |
title->angle_count = 0;
|
|
Packit |
5e46da |
title->angle = angle;
|
|
Packit |
5e46da |
title->pl = mpls_get(disc, playlist);
|
|
Packit |
5e46da |
if (title->pl == NULL) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV, "Fail: Playlist parse %s\n", playlist);
|
|
Packit |
5e46da |
X_FREE(title);
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Find length in packets and end_pkt for each clip
|
|
Packit |
5e46da |
title->clip_list.count = title->pl->list_count;
|
|
Packit |
5e46da |
title->clip_list.clip = calloc(title->pl->list_count, sizeof(NAV_CLIP));
|
|
Packit |
5e46da |
title->packets = 0;
|
|
Packit |
5e46da |
for (ii = 0; ii < title->pl->list_count; ii++) {
|
|
Packit |
5e46da |
MPLS_PI *pi;
|
|
Packit |
5e46da |
NAV_CLIP *clip;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
pi = &title->pl->play_item[ii];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
clip = &title->clip_list.clip[ii];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_fill_clip(title, pi->clip, pi->connection_condition, pi->in_time, pi->out_time, pi->angle_count,
|
|
Packit |
5e46da |
clip, ii, &pos, &time);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// sub paths
|
|
Packit |
5e46da |
// Find length in packets and end_pkt for each clip
|
|
Packit |
5e46da |
if (title->pl->sub_count > 0) {
|
|
Packit |
5e46da |
title->sub_path_count = title->pl->sub_count;
|
|
Packit |
5e46da |
title->sub_path = calloc(title->sub_path_count, sizeof(NAV_SUB_PATH));
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ss = 0; ss < title->sub_path_count; ss++) {
|
|
Packit |
5e46da |
NAV_SUB_PATH *sub_path = &title->sub_path[ss];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
sub_path->type = title->pl->sub_path[ss].type;
|
|
Packit |
5e46da |
sub_path->clip_list.count = title->pl->sub_path[ss].sub_playitem_count;
|
|
Packit |
5e46da |
sub_path->clip_list.clip = calloc(sub_path->clip_list.count, sizeof(NAV_CLIP));
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
pos = time = 0;
|
|
Packit |
5e46da |
for (ii = 0; ii < sub_path->clip_list.count; ii++) {
|
|
Packit |
5e46da |
MPLS_SUB_PI *pi = &title->pl->sub_path[ss].sub_play_item[ii];
|
|
Packit |
5e46da |
NAV_CLIP *clip = &sub_path->clip_list.clip[ii];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_fill_clip(title, pi->clip, pi->connection_condition, pi->in_time, pi->out_time, 0,
|
|
Packit |
5e46da |
clip, ii, &pos, &time);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
title->chap_list.count = _pl_chapter_count(title->pl);
|
|
Packit |
5e46da |
title->chap_list.mark = calloc(title->chap_list.count, sizeof(NAV_MARK));
|
|
Packit |
5e46da |
title->mark_list.count = title->pl->mark_count;
|
|
Packit |
5e46da |
title->mark_list.mark = calloc(title->pl->mark_count, sizeof(NAV_MARK));
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_extrapolate_title(title);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (title->angle >= title->angle_count) {
|
|
Packit |
5e46da |
title->angle = 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return title;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static
|
|
Packit |
5e46da |
void _nav_title_close(NAV_TITLE *title)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned ii, ss;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (title->sub_path) {
|
|
Packit |
5e46da |
for (ss = 0; ss < title->sub_path_count; ss++) {
|
|
Packit |
5e46da |
if (title->sub_path[ss].clip_list.clip) {
|
|
Packit |
5e46da |
for (ii = 0; ii < title->sub_path[ss].clip_list.count; ii++) {
|
|
Packit |
5e46da |
clpi_free(&title->sub_path[ss].clip_list.clip[ii].cl);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE(title->sub_path[ss].clip_list.clip);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE(title->sub_path);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (title->clip_list.clip) {
|
|
Packit |
5e46da |
for (ii = 0; ii < title->clip_list.count; ii++) {
|
|
Packit |
5e46da |
clpi_free(&title->clip_list.clip[ii].cl);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE(title->clip_list.clip);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
mpls_free(&title->pl);
|
|
Packit |
5e46da |
X_FREE(title->chap_list.mark);
|
|
Packit |
5e46da |
X_FREE(title->mark_list.mark);
|
|
Packit |
5e46da |
X_FREE(title);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
void nav_title_close(NAV_TITLE **title)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (*title) {
|
|
Packit |
5e46da |
_nav_title_close(*title);
|
|
Packit |
5e46da |
*title = NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Search for random access point closest to the requested packet
|
|
Packit |
5e46da |
// Packets are 192 byte TS packets
|
|
Packit |
5e46da |
NAV_CLIP* nav_chapter_search(NAV_TITLE *title, unsigned chapter, uint32_t *clip_pkt, uint32_t *out_pkt)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
NAV_CLIP *clip;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (chapter > title->chap_list.count) {
|
|
Packit |
5e46da |
clip = &title->clip_list.clip[0];
|
|
Packit |
5e46da |
*clip_pkt = clip->start_pkt;
|
|
Packit |
5e46da |
*out_pkt = clip->title_pkt;
|
|
Packit |
5e46da |
return clip;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
clip = &title->clip_list.clip[title->chap_list.mark[chapter].clip_ref];
|
|
Packit |
5e46da |
*clip_pkt = title->chap_list.mark[chapter].clip_pkt;
|
|
Packit |
5e46da |
*out_pkt = clip->title_pkt + *clip_pkt - clip->start_pkt;
|
|
Packit |
5e46da |
return clip;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
uint32_t nav_chapter_get_current(NAV_TITLE * title, uint32_t title_pkt)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
NAV_MARK * mark;
|
|
Packit |
5e46da |
uint32_t ii;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (title == NULL) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
for (ii = 0; ii < title->chap_list.count; ii++) {
|
|
Packit |
5e46da |
mark = &title->chap_list.mark[ii];
|
|
Packit |
5e46da |
if (mark->title_pkt <= title_pkt) {
|
|
Packit |
5e46da |
if ( ii == title->chap_list.count - 1 ) {
|
|
Packit |
5e46da |
return ii;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
mark = &title->chap_list.mark[ii+1];
|
|
Packit |
5e46da |
if (mark->title_pkt > title_pkt) {
|
|
Packit |
5e46da |
return ii;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Search for random access point closest to the requested packet
|
|
Packit |
5e46da |
// Packets are 192 byte TS packets
|
|
Packit |
5e46da |
NAV_CLIP* nav_mark_search(NAV_TITLE *title, unsigned mark, uint32_t *clip_pkt, uint32_t *out_pkt)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
NAV_CLIP *clip;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (mark > title->mark_list.count) {
|
|
Packit |
5e46da |
clip = &title->clip_list.clip[0];
|
|
Packit |
5e46da |
*clip_pkt = clip->start_pkt;
|
|
Packit |
5e46da |
*out_pkt = clip->title_pkt;
|
|
Packit |
5e46da |
return clip;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
clip = &title->clip_list.clip[title->mark_list.mark[mark].clip_ref];
|
|
Packit |
5e46da |
*clip_pkt = title->mark_list.mark[mark].clip_pkt;
|
|
Packit |
5e46da |
*out_pkt = clip->title_pkt + *clip_pkt - clip->start_pkt;
|
|
Packit |
5e46da |
return clip;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
void nav_clip_packet_search(NAV_CLIP *clip, uint32_t pkt, uint32_t *clip_pkt, uint32_t *clip_time)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
*clip_time = clip->in_time;
|
|
Packit |
5e46da |
if (clip->cl != NULL) {
|
|
Packit |
5e46da |
*clip_pkt = clpi_access_point(clip->cl, pkt, 0, 0, clip_time);
|
|
Packit |
5e46da |
if (*clip_pkt < clip->start_pkt) {
|
|
Packit |
5e46da |
*clip_pkt = clip->start_pkt;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (*clip_time && *clip_time < clip->in_time) {
|
|
Packit |
5e46da |
/* EP map does not store lowest 8 bits of timestamp */
|
|
Packit |
5e46da |
*clip_time = clip->in_time;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
*clip_pkt = clip->start_pkt;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Search for random access point closest to the requested packet
|
|
Packit |
5e46da |
// Packets are 192 byte TS packets
|
|
Packit |
5e46da |
// pkt is relative to the beginning of the title
|
|
Packit |
5e46da |
// out_pkt and out_time is relative to the the clip which the packet falls in
|
|
Packit |
5e46da |
NAV_CLIP* nav_packet_search(NAV_TITLE *title, uint32_t pkt, uint32_t *clip_pkt, uint32_t *out_pkt, uint32_t *out_time)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
uint32_t pos, len;
|
|
Packit |
5e46da |
NAV_CLIP *clip;
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
*out_time = 0;
|
|
Packit |
5e46da |
pos = 0;
|
|
Packit |
5e46da |
for (ii = 0; ii < title->pl->list_count; ii++) {
|
|
Packit |
5e46da |
clip = &title->clip_list.clip[ii];
|
|
Packit |
5e46da |
len = clip->end_pkt - clip->start_pkt;
|
|
Packit |
5e46da |
if (pkt < pos + len)
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
pos += len;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (ii == title->pl->list_count) {
|
|
Packit |
5e46da |
clip = &title->clip_list.clip[ii-1];
|
|
Packit |
5e46da |
*out_time = clip->duration + clip->in_time;
|
|
Packit |
5e46da |
*clip_pkt = clip->end_pkt;
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
clip = &title->clip_list.clip[ii];
|
|
Packit |
5e46da |
nav_clip_packet_search(clip, pkt - pos + clip->start_pkt, clip_pkt, out_time);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if(*out_time < clip->in_time)
|
|
Packit |
5e46da |
*out_time = 0;
|
|
Packit |
5e46da |
else
|
|
Packit |
5e46da |
*out_time -= clip->in_time;
|
|
Packit |
5e46da |
*out_pkt = clip->title_pkt + *clip_pkt - clip->start_pkt;
|
|
Packit |
5e46da |
return clip;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Search for the nearest random access point after the given pkt
|
|
Packit |
5e46da |
// which is an angle change point.
|
|
Packit |
5e46da |
// Packets are 192 byte TS packets
|
|
Packit |
5e46da |
// pkt is relative to the clip
|
|
Packit |
5e46da |
// time is the clip relative time where the angle change point occurs
|
|
Packit |
5e46da |
// returns a packet number
|
|
Packit |
5e46da |
//
|
|
Packit |
5e46da |
// To perform a seamless angle change, perform the following sequence:
|
|
Packit |
5e46da |
// 1. Find the next angle change point with nav_angle_change_search.
|
|
Packit |
5e46da |
// 2. Read and process packets until the angle change point is reached.
|
|
Packit |
5e46da |
// This may mean progressing to the next play item if the angle change
|
|
Packit |
5e46da |
// point is at the end of the current play item.
|
|
Packit |
5e46da |
// 3. Change angles with nav_set_angle. Changing angles means changing
|
|
Packit |
5e46da |
// m2ts files. The new clip information is returned from nav_set_angle.
|
|
Packit |
5e46da |
// 4. Close the current m2ts file and open the new one returned
|
|
Packit |
5e46da |
// from nav_set_angle.
|
|
Packit |
5e46da |
// 4. If the angle change point was within the time period of the current
|
|
Packit |
5e46da |
// play item (i.e. the angle change point is not at the end of the clip),
|
|
Packit |
5e46da |
// Search to the timestamp obtained from nav_angle_change_search using
|
|
Packit |
5e46da |
// nav_clip_time_search. Otherwise start at the start_pkt defined
|
|
Packit |
5e46da |
// by the clip.
|
|
Packit |
5e46da |
uint32_t nav_angle_change_search(NAV_CLIP *clip, uint32_t pkt, uint32_t *time)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (clip->cl == NULL) {
|
|
Packit |
5e46da |
return pkt;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
return clpi_access_point(clip->cl, pkt, 1, 1, time);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Search for random access point closest to the requested time
|
|
Packit |
5e46da |
// Time is in 45khz ticks
|
|
Packit |
5e46da |
NAV_CLIP* nav_time_search(NAV_TITLE *title, uint32_t tick, uint32_t *clip_pkt, uint32_t *out_pkt)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
uint32_t pos, len;
|
|
Packit |
5e46da |
MPLS_PI *pi = NULL;
|
|
Packit |
5e46da |
NAV_CLIP *clip;
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!title->pl) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "Time search failed (title not opened)\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (title->pl->list_count < 1) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_NAV | DBG_CRIT, "Time search failed (empty playlist)\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
pos = 0;
|
|
Packit |
5e46da |
for (ii = 0; ii < title->pl->list_count; ii++) {
|
|
Packit |
5e46da |
pi = &title->pl->play_item[ii];
|
|
Packit |
5e46da |
len = pi->out_time - pi->in_time;
|
|
Packit |
5e46da |
if (tick < pos + len)
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
pos += len;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (ii == title->pl->list_count) {
|
|
Packit |
5e46da |
clip = &title->clip_list.clip[ii-1];
|
|
Packit |
5e46da |
*clip_pkt = clip->end_pkt;
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
clip = &title->clip_list.clip[ii];
|
|
Packit |
5e46da |
nav_clip_time_search(clip, tick - pos + pi->in_time, clip_pkt, out_pkt);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
*out_pkt = clip->title_pkt + *clip_pkt - clip->start_pkt;
|
|
Packit |
5e46da |
return clip;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Search for random access point closest to the requested time
|
|
Packit |
5e46da |
// Time is in 45khz ticks, between clip in_time and out_time.
|
|
Packit |
5e46da |
void nav_clip_time_search(NAV_CLIP *clip, uint32_t tick, uint32_t *clip_pkt, uint32_t *out_pkt)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (tick >= clip->out_time) {
|
|
Packit |
5e46da |
*clip_pkt = clip->end_pkt;
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
if (clip->cl != NULL) {
|
|
Packit |
5e46da |
*clip_pkt = clpi_lookup_spn(clip->cl, tick, 1,
|
|
Packit |
5e46da |
clip->title->pl->play_item[clip->ref].clip[clip->angle].stc_id);
|
|
Packit |
5e46da |
if (*clip_pkt < clip->start_pkt) {
|
|
Packit |
5e46da |
*clip_pkt = clip->start_pkt;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
*clip_pkt = clip->start_pkt;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
*out_pkt = clip->title_pkt + *clip_pkt - clip->start_pkt;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* Input Parameters:
|
|
Packit |
5e46da |
* title - title struct obtained from nav_title_open
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* Return value:
|
|
Packit |
5e46da |
* Pointer to NAV_CLIP struct
|
|
Packit |
5e46da |
* NULL - End of clip list
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
NAV_CLIP* nav_next_clip(NAV_TITLE *title, NAV_CLIP *clip)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (clip == NULL) {
|
|
Packit |
5e46da |
return &title->clip_list.clip[0];
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (clip->ref >= title->clip_list.count - 1) {
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
return &title->clip_list.clip[clip->ref + 1];
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
NAV_CLIP* nav_set_angle(NAV_TITLE *title, NAV_CLIP *clip, unsigned angle)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int ii;
|
|
Packit |
5e46da |
uint32_t pos = 0;
|
|
Packit |
5e46da |
uint32_t time = 0;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (title == NULL) {
|
|
Packit |
5e46da |
return clip;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (angle > 8) {
|
|
Packit |
5e46da |
// invalid angle
|
|
Packit |
5e46da |
return clip;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (angle == title->angle) {
|
|
Packit |
5e46da |
// no change
|
|
Packit |
5e46da |
return clip;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
title->angle = angle;
|
|
Packit |
5e46da |
// Find length in packets and end_pkt for each clip
|
|
Packit |
5e46da |
title->packets = 0;
|
|
Packit |
5e46da |
for (ii = 0; ii < title->pl->list_count; ii++) {
|
|
Packit |
5e46da |
MPLS_PI *pi;
|
|
Packit |
5e46da |
NAV_CLIP *cl;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
pi = &title->pl->play_item[ii];
|
|
Packit |
5e46da |
cl = &title->clip_list.clip[ii];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_fill_clip(title, pi->clip, pi->connection_condition, pi->in_time, pi->out_time, pi->angle_count,
|
|
Packit |
5e46da |
cl, ii, &pos, &time);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
_extrapolate_title(title);
|
|
Packit |
5e46da |
return clip;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|