You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
257 lines
6.7 KiB
257 lines
6.7 KiB
/*
|
|
* section and descriptor parser
|
|
*
|
|
* Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include "transport_packet.h"
|
|
|
|
#define CONTINUITY_VALID 0x80
|
|
#define CONTINUITY_DUPESEEN 0x40
|
|
|
|
int transport_packet_values_extract(struct transport_packet *pkt,
|
|
struct transport_values *out,
|
|
enum transport_value extract)
|
|
{
|
|
uint8_t *end = (uint8_t*) pkt + TRANSPORT_PACKET_LENGTH;
|
|
uint8_t *adapend;
|
|
uint8_t *pos = (uint8_t*) pkt + sizeof(struct transport_packet);
|
|
enum transport_value extracted = 0;
|
|
enum transport_adaptation_flags adapflags = 0;
|
|
enum transport_adaptation_extension_flags adapextflags = 0;
|
|
int adaplength = 0;
|
|
int adapextlength = 0;
|
|
|
|
/* does the packet contain an adaptation field ? */
|
|
if ((pkt->adaptation_field_control & 2) == 0)
|
|
goto extract_payload;
|
|
|
|
/* get the adaptation field length and skip the byte */
|
|
adaplength = *pos++;
|
|
|
|
/* do we actually have any adaptation data? */
|
|
if (adaplength == 0)
|
|
goto extract_payload;
|
|
|
|
/* sanity check */
|
|
adapend = pos + adaplength;
|
|
if (adapend > end)
|
|
return -1;
|
|
|
|
/* extract the adaptation flags (we must have at least 1 byte to be here) */
|
|
adapflags = *pos++;
|
|
|
|
/* do we actually want anything else? */
|
|
if ((extract & 0xffff) == 0)
|
|
goto extract_payload;
|
|
|
|
/* PCR? */
|
|
if (adapflags & transport_adaptation_flag_pcr) {
|
|
if ((pos+6) > adapend)
|
|
return -1;
|
|
|
|
if (extract & transport_value_pcr) {
|
|
uint64_t base = ((uint64_t) pos[0] << 25) |
|
|
((uint64_t) pos[1] << 17) |
|
|
((uint64_t) pos[2] << 9) |
|
|
((uint64_t) pos[3] << 1) |
|
|
((uint64_t) pos[4] >> 7);
|
|
uint64_t ext = (((uint64_t) pos[4] & 1) << 8) |
|
|
(uint64_t) pos[5];
|
|
out->pcr= base * 300ULL + ext;
|
|
extracted |= transport_value_pcr;
|
|
}
|
|
pos += 6;
|
|
}
|
|
|
|
/* OPCR? */
|
|
if (adapflags & transport_adaptation_flag_opcr) {
|
|
if ((pos+6) > adapend)
|
|
return -1;
|
|
|
|
if (extract & transport_value_opcr) {
|
|
uint64_t base = ((uint64_t) pos[0] << 25) |
|
|
((uint64_t) pos[1] << 17) |
|
|
((uint64_t) pos[2] << 9) |
|
|
((uint64_t) pos[3] << 1) |
|
|
((uint64_t) pos[4] >> 7);
|
|
uint64_t ext = (((uint64_t) pos[4] & 1) << 8) |
|
|
(uint64_t) pos[5];
|
|
out->opcr= base * 300ULL + ext;
|
|
extracted |= transport_value_opcr;
|
|
}
|
|
pos += 6;
|
|
}
|
|
|
|
/* splice countdown? */
|
|
if (adapflags & transport_adaptation_flag_splicing_point) {
|
|
if ((pos+1) > adapend)
|
|
return -1;
|
|
|
|
if (extract & transport_value_splice_countdown) {
|
|
out->splice_countdown = *pos;
|
|
extracted |= transport_value_splice_countdown;
|
|
}
|
|
pos++;
|
|
}
|
|
|
|
/* private data? */
|
|
if (adapflags & transport_adaptation_flag_private_data) {
|
|
if ((pos+1) > adapend)
|
|
return -1;
|
|
if ((pos+1+*pos) > adapend)
|
|
return -1;
|
|
|
|
if (extract & transport_value_private_data) {
|
|
out->private_data_length = *pos;
|
|
out->private_data = pos + 1;
|
|
extracted |= transport_value_private_data;
|
|
}
|
|
pos += 1 + *pos;
|
|
}
|
|
|
|
/* is there an adaptation extension? */
|
|
if (!(adapflags & transport_adaptation_flag_extension))
|
|
goto extract_payload;
|
|
|
|
/* get/check the length */
|
|
if (pos >= adapend)
|
|
return -1;
|
|
adapextlength = *pos++;
|
|
if ((pos + adapextlength) > adapend)
|
|
return -1;
|
|
|
|
/* do we want/have anything in the adaptation extension? */
|
|
if (((extract & 0xff00) == 0) || (adapextlength == 0))
|
|
goto extract_payload;
|
|
|
|
/* extract the adaptation extension flags (we must have at least 1 byte
|
|
* to be here) */
|
|
adapextflags = *pos++;
|
|
|
|
/* LTW? */
|
|
if (adapextflags & transport_adaptation_extension_flag_ltw) {
|
|
if ((pos+2) > adapend)
|
|
return -1;
|
|
|
|
if (extract & transport_value_ltw) {
|
|
if (*pos & 0x80) {
|
|
out->ltw_offset = ((pos[0] & 0x7f) << 8) |
|
|
(pos[1]);
|
|
extracted |= transport_value_ltw;
|
|
}
|
|
}
|
|
pos += 2;
|
|
}
|
|
|
|
/* piecewise_rate? */
|
|
if (adapextflags & transport_adaptation_extension_flag_piecewise_rate) {
|
|
if ((pos+3) > adapend)
|
|
return -1;
|
|
|
|
if (extract & transport_value_piecewise_rate) {
|
|
out->piecewise_rate = ((pos[0] & 0x3f) << 16) |
|
|
(pos[1] << 8) |
|
|
pos[2];
|
|
extracted |= transport_value_piecewise_rate;
|
|
}
|
|
pos += 3;
|
|
}
|
|
|
|
/* seamless_splice? */
|
|
if (adapextflags & transport_adaptation_extension_flag_seamless_splice) {
|
|
if ((pos+5) > adapend)
|
|
return -1;
|
|
|
|
if (extract & transport_value_piecewise_rate) {
|
|
out->splice_type = pos[0] >> 4;
|
|
out->dts_next_au = ((pos[0] & 0x0e) << 29) |
|
|
(pos[1] << 22) |
|
|
((pos[2] & 0xfe) << 14) |
|
|
(pos[3] << 7) |
|
|
((pos[4] & 0xfe) >> 1);
|
|
extracted |= transport_value_seamless_splice;
|
|
}
|
|
pos += 5;
|
|
}
|
|
|
|
|
|
|
|
extract_payload:
|
|
/* does the packet contain a payload? */
|
|
if (pkt->adaptation_field_control & 1) {
|
|
int off = sizeof(struct transport_packet);
|
|
if (pkt->adaptation_field_control & 2)
|
|
off++;
|
|
off += adaplength;
|
|
|
|
out->payload = (uint8_t*) pkt + off;
|
|
out->payload_length = TRANSPORT_PACKET_LENGTH - off;
|
|
} else {
|
|
out->payload = NULL;
|
|
out->payload_length = 0;
|
|
}
|
|
|
|
out->flags = adapflags;
|
|
return extracted;
|
|
}
|
|
|
|
int transport_packet_continuity_check(struct transport_packet *pkt,
|
|
int discontinuity_indicator, unsigned char *cstate)
|
|
{
|
|
unsigned char pktcontinuity = pkt->continuity_counter;
|
|
unsigned char prevcontinuity = *cstate & 0x0f;
|
|
unsigned char nextcontinuity;
|
|
|
|
/* NULL packets have undefined continuity */
|
|
if (transport_packet_pid(pkt) == TRANSPORT_NULL_PID)
|
|
return 0;
|
|
|
|
/* is the state valid? */
|
|
if (!(*cstate & CONTINUITY_VALID)) {
|
|
*cstate = pktcontinuity | CONTINUITY_VALID;
|
|
return 0;
|
|
}
|
|
|
|
/* check for discontinuity_indicator */
|
|
if (discontinuity_indicator) {
|
|
*cstate = pktcontinuity | CONTINUITY_VALID;
|
|
return 0;
|
|
}
|
|
|
|
/* only packets with a payload should increment the counter */
|
|
if (pkt->adaptation_field_control & 1)
|
|
nextcontinuity = (prevcontinuity + 1) & 0xf;
|
|
else
|
|
nextcontinuity = prevcontinuity;
|
|
|
|
/* check for a normal continuity progression */
|
|
if (nextcontinuity == pktcontinuity) {
|
|
*cstate = pktcontinuity | CONTINUITY_VALID;
|
|
return 0;
|
|
}
|
|
|
|
/* one dupe is allowed */
|
|
if ((prevcontinuity == pktcontinuity) && (!(*cstate & CONTINUITY_DUPESEEN))) {
|
|
*cstate = pktcontinuity | (CONTINUITY_VALID|CONTINUITY_DUPESEEN);
|
|
return 0;
|
|
}
|
|
|
|
/* continuity error */
|
|
return -1;
|
|
}
|