|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* This file is part of libbluray
|
|
Packit |
5e46da |
* Copyright (C) 2010 hpi1
|
|
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 "m2ts_demux.h"
|
|
Packit |
5e46da |
#include "pes_buffer.h"
|
|
Packit |
5e46da |
|
|
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 M2TS_TRACE(...) BD_DEBUG(DBG_CRIT,__VA_ARGS__)*/
|
|
Packit |
5e46da |
#define M2TS_TRACE(...) do {} while(0)
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
struct m2ts_demux_s
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
uint16_t pid;
|
|
Packit |
5e46da |
uint32_t pes_length;
|
|
Packit |
5e46da |
PES_BUFFER *buf;
|
|
Packit |
5e46da |
};
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static PES_BUFFER *_flush(M2TS_DEMUX *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
PES_BUFFER *result = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
result = p->buf;
|
|
Packit |
5e46da |
p->buf = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return result;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
void m2ts_demux_reset(M2TS_DEMUX *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (p) {
|
|
Packit |
5e46da |
PES_BUFFER *buf = _flush(p);
|
|
Packit |
5e46da |
pes_buffer_free(&buf;;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
M2TS_DEMUX *m2ts_demux_init(uint16_t pid)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
M2TS_DEMUX *p = calloc(1, sizeof(*p));
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (p) {
|
|
Packit |
5e46da |
p->pid = pid;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return p;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
void m2ts_demux_free(M2TS_DEMUX **p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (p && *p) {
|
|
Packit |
5e46da |
m2ts_demux_reset(*p);
|
|
Packit |
5e46da |
X_FREE(*p);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _realloc(PES_BUFFER *p, size_t size)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
uint8_t *tmp = realloc(p->buf, size);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!tmp) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_DECODE | DBG_CRIT, "out of memory\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->size = size;
|
|
Packit |
5e46da |
p->buf = tmp;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _add_ts(PES_BUFFER *p, uint8_t *buf, unsigned len)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
// realloc
|
|
Packit |
5e46da |
if (p->size < p->len + len) {
|
|
Packit |
5e46da |
if (_realloc(p, p->size * 2) < 0) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// append
|
|
Packit |
5e46da |
memcpy(p->buf + p->len, buf, len);
|
|
Packit |
5e46da |
p->len += len;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* Parsing
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int64_t _parse_timestamp(uint8_t *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int64_t ts;
|
|
Packit |
5e46da |
ts = ((int64_t)(p[0] & 0x0E)) << 29;
|
|
Packit |
5e46da |
ts |= p[1] << 22;
|
|
Packit |
5e46da |
ts |= (p[2] & 0xFE) << 14;
|
|
Packit |
5e46da |
ts |= p[3] << 7;
|
|
Packit |
5e46da |
ts |= (p[4] & 0xFE) >> 1;
|
|
Packit |
5e46da |
return ts;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _parse_pes(PES_BUFFER *p, uint8_t *buf, unsigned len)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int result = 0;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (len < 6) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_DECODE, "invalid BDAV TS (PES header not in single TS packet)\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (buf[0] || buf[1] || buf[2] != 1) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_DECODE, "invalid PES header (00 00 01)");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// Parse PES header
|
|
Packit |
5e46da |
unsigned pes_pid = buf[3];
|
|
Packit |
5e46da |
unsigned pes_length = buf[4] << 8 | buf[5];
|
|
Packit |
5e46da |
unsigned hdr_len = 6;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (pes_pid != 0xbf) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (len < 9) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_DECODE, "invalid BDAV TS (PES header not in single TS packet)\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
unsigned pts_exists = buf[7] & 0x80;
|
|
Packit |
5e46da |
unsigned dts_exists = buf[7] & 0x40;
|
|
Packit |
5e46da |
hdr_len += buf[8] + 3;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (len < hdr_len) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_DECODE, "invalid BDAV TS (PES header not in single TS packet)\n");
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (pts_exists) {
|
|
Packit |
5e46da |
p->pts = _parse_timestamp(buf + 9);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (dts_exists) {
|
|
Packit |
5e46da |
p->dts = _parse_timestamp(buf + 14);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
result = pes_length + 6 - hdr_len;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (_realloc(p, BD_MAX(result, 0x100)) < 0) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
p->len = len - hdr_len;
|
|
Packit |
5e46da |
memcpy(p->buf, buf + hdr_len, p->len);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return result;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
PES_BUFFER *m2ts_demux(M2TS_DEMUX *p, uint8_t *buf)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
uint8_t *end = buf + 6144;
|
|
Packit |
5e46da |
PES_BUFFER *result = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!buf) {
|
|
Packit |
5e46da |
return _flush(p);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (; buf < end; buf += 192) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
unsigned tp_error = buf[4+1] & 0x80;
|
|
Packit |
5e46da |
unsigned pusi = buf[4+1] & 0x40;
|
|
Packit |
5e46da |
uint16_t pid = ((buf[4+1] & 0x1f) << 8) | buf[4+2];
|
|
Packit |
5e46da |
unsigned payload_exists = buf[4+3] & 0x10;
|
|
Packit |
5e46da |
int payload_offset = (buf[4+3] & 0x20) ? buf[4+4] + 5 : 4;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (buf[4] != 0x47) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_DECODE, "missing sync byte. scrambled data ?\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (pid != p->pid) {
|
|
Packit |
5e46da |
M2TS_TRACE("skipping packet (pid %d)\n", pid);
|
|
Packit |
5e46da |
continue;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (tp_error) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_DECODE, "skipping packet (transport error)\n");
|
|
Packit |
5e46da |
continue;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (!payload_exists) {
|
|
Packit |
5e46da |
M2TS_TRACE("skipping packet (no payload)\n");
|
|
Packit |
5e46da |
continue;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (payload_offset >= 188) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_DECODE, "skipping packet (invalid payload start address)\n");
|
|
Packit |
5e46da |
continue;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (pusi) {
|
|
Packit |
5e46da |
if (p->buf) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_DECODE, "PES length mismatch: have %d, expected %d\n",
|
|
Packit |
5e46da |
p->buf->len, p->pes_length);
|
|
Packit |
5e46da |
pes_buffer_free(&p->buf);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
p->buf = pes_buffer_alloc();
|
|
Packit |
5e46da |
if (!p->buf) {
|
|
Packit |
5e46da |
continue;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
int r = _parse_pes(p->buf, buf + 4 + payload_offset, 188 - payload_offset);
|
|
Packit |
5e46da |
if (r < 0) {
|
|
Packit |
5e46da |
pes_buffer_free(&p->buf);
|
|
Packit |
5e46da |
continue;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
p->pes_length = r;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!p->buf) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_DECODE, "skipping packet (no pusi seen)\n");
|
|
Packit |
5e46da |
continue;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (_add_ts(p->buf, buf + 4 + payload_offset, 188 - payload_offset) < 0) {
|
|
Packit |
5e46da |
pes_buffer_free(&p->buf);
|
|
Packit |
5e46da |
continue;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (p->buf->len == p->pes_length) {
|
|
Packit |
5e46da |
M2TS_TRACE("PES complete (%d bytes)\n", p->pes_length);
|
|
Packit |
5e46da |
pes_buffer_append(&result, p->buf);
|
|
Packit |
5e46da |
p->buf = NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return result;
|
|
Packit |
5e46da |
}
|