Mailing List archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[vdr] Re: bitstreamout-0.48pre5



On Wed, Oct 29, 2003 at 01:21:51AM +0200, Sven Goethel wrote:
Content-Description: clearsigned data
> On Tuesday 28 October 2003 11:47, Dr. Werner Fink wrote:
> > What is the difference between pts and stc?
> > I'd like to know if there is a static offset
> > of 1 second ... more or less ... for live
> > mode.
> 
> not that bad as you can see ..
> 
> negativ value: pts > stc: audio is earlier than video
> positiv value: stc > pts: audio arrives too late
> 
> if the value is negativ - earlier - keep in mind,
> that still some time (1-5 ms) will be taken to:
> 	- put the data to spdif (about 1ms)
> 	- xform the data to pcm (mp2 only, about 1-5ms)

A difference of +/- 5 ms you can ignore (10 ms are 33cm) ... most
people are not able to distinguish between +/- 5 ms if all channels
have the _same_ offset.  Only difference between e.g. left and
right channels are significant and this is never the case.

> 
> especially the zdf ac3 case looks promising, 
> 'cause audio arrives here always earlier.
> e.g. ac3 can be made in sync via stc diff usleep !
> (be sure to set bitstreamout option delay to zero)

Hmmm ... what so you think about not usleep(ing) but simply
playing silence.
 
> but all mp2 cases are about 50ms too late,
> you can ignore the "earlier" values here .. 'cause
> extra time is needed for decoding - so no action is taken here.

How long does decoding take?

> 
> testing the audio mp2 sync, with audio overlay listening
> - - listening to sndcard audio-out: parallel mp2 out and analog loop
> through - you will hear a little echo about 50-200ms .. das bad.

This is really bad.

> 
> so the final question is:
> 
> why appears ac3 audio "in time" ( -5ms ),
> but mp2 audio always too late ( 50ms and more ) ???

Hmmm ... you need some recordings to analyse the bitstream its
self.  I'll append my current xlist.c C++ program which is able
to show PTS of the audio, video and ps1 streams. should be
compiled with

   g++ -O2 -pipe -funroll-loops -Wall -D_GNU_SOURCE -o xlist xlist.c

you can simply do

   xlist 001.vdr | less -S

or

   xlist -s 001.vdr | less -S

to analyse the stream (xlist -h shows the possible options).
How the other channels do their streams (Sat1, Pro7 also uses AC3)?

> stc-pts_ac3_zdf.txt
> PTSDIFF stc-pts: 19741107ms - 19741112ms =   -5ms,  slept   13ms
> PTSDIFF stc-pts: 19741267ms - 19741272ms =   -5ms,  slept   13ms
> PTSDIFF stc-pts: 19741427ms - 19741432ms =   -5ms,  slept   13ms
> PTSDIFF stc-pts: 19741587ms - 19741592ms =   -5ms,  slept   13ms
> PTSDIFF stc-pts: 19741747ms - 19741752ms =   -5ms,  slept   12ms
> PTSDIFF stc-pts: 19741907ms - 19741912ms =   -5ms,  slept   13ms
> PTSDIFF stc-pts: 19742067ms - 19742072ms =   -5ms,  slept   13ms
> PTSDIFF stc-pts: 19742227ms - 19742232ms =   -5ms,  slept   13ms
> PTSDIFF stc-pts: 19742387ms - 19742392ms =   -5ms,  slept   13ms
> PTSDIFF stc-pts: 19742547ms - 19742552ms =   -5ms,  slept   12ms
> PTSDIFF stc-pts: 19742707ms - 19742712ms =   -5ms,  slept   13ms
> PTSDIFF stc-pts: 19742867ms - 19742872ms =   -5ms,  slept   13ms

Continous stream, perfect.

> stc-pts_mp2_ard.txt
> PTSDIFF stc-pts: 9708836ms - 9708846ms =  -10ms, 
> PTSDIFF stc-pts: 9708914ms - 9708918ms =   -4ms, 
> PTSDIFF stc-pts: 9708988ms - 9709014ms =  -26ms, 
> PTSDIFF stc-pts: 9709106ms - 9709086ms =   20ms,  mp2dec delay    20ms
> PTSDIFF stc-pts: 9709154ms - 9709158ms =   -4ms, 
> PTSDIFF stc-pts: 9709219ms - 9709230ms =  -11ms, 
> PTSDIFF stc-pts: 9709346ms - 9709302ms =   44ms,  mp2dec delay    44ms
> PTSDIFF stc-pts: 9709372ms - 9709374ms =   -2ms, 
> PTSDIFF stc-pts: 9709447ms - 9709470ms =  -23ms, 
> PTSDIFF stc-pts: 9709522ms - 9709542ms =  -20ms, 
> PTSDIFF stc-pts: 9709602ms - 9709614ms =  -12ms, 
> PTSDIFF stc-pts: 9709671ms - 9709686ms =  -15ms, 
> PTSDIFF stc-pts: 9709748ms - 9709758ms =  -10ms, 
> PTSDIFF stc-pts: 9709858ms - 9709830ms =   28ms,  mp2dec delay    28ms
> PTSDIFF stc-pts: 9709897ms - 9709926ms =  -29ms, 
> PTSDIFF stc-pts: 9709984ms - 9709998ms =  -14ms, 
> PTSDIFF stc-pts: 9710082ms - 9710070ms =   12ms,  mp2dec delay    12ms
> PTSDIFF stc-pts: 9710130ms - 9710142ms =  -12ms, 
> PTSDIFF stc-pts: 9710203ms - 9710214ms =  -11ms, 
> PTSDIFF stc-pts: 9710338ms - 9710286ms =   52ms,  mp2dec delay    52ms
> PTSDIFF stc-pts: 9710348ms - 9710382ms =  -34ms, 
> PTSDIFF stc-pts: 9710450ms - 9710454ms =   -4ms, 
> PTSDIFF stc-pts: 9710530ms - 9710526ms =    4ms,  mp2dec delay     4ms
> PTSDIFF stc-pts: 9710574ms - 9710598ms =  -24ms, 
> PTSDIFF stc-pts: 9710690ms - 9710670ms =   20ms,  mp2dec delay    20ms
> PTSDIFF stc-pts: 9710734ms - 9710742ms =   -8ms, 

OK ... this could be handled by buffering (ring buffer _and_ hw
buffer of the sound card). But IMHO the timing of this audio stream
is broken (as all channels on this transponder) ... it seesm that
ARD has changed their encoder.  Currently I hear that the audio
on all channels on transponder 11837 is shuttering due to this bad
timing.  Only if you catch a small delay at start you're able
to smooth out the unstable audio stream by buffering it.

> stc-pts_mp2_zdf.txt
> PTSDIFF stc-pts: 19657305ms - 19657308ms =   -3ms, 
> PTSDIFF stc-pts: 19657474ms - 19657476ms =   -2ms, 
> PTSDIFF stc-pts: 19657644ms - 19657644ms =    0ms, 
> PTSDIFF stc-pts: 19657809ms - 19657812ms =   -3ms, 
> PTSDIFF stc-pts: 19657985ms - 19657980ms =    5ms,  mp2dec delay     5ms
> PTSDIFF stc-pts: 19658153ms - 19658148ms =    5ms,  mp2dec delay     5ms
> PTSDIFF stc-pts: 19658318ms - 19658316ms =    2ms,  mp2dec delay     2ms
> PTSDIFF stc-pts: 19658488ms - 19658484ms =    4ms,  mp2dec delay     4ms
> PTSDIFF stc-pts: 19658657ms - 19658652ms =    5ms,  mp2dec delay     5ms
> PTSDIFF stc-pts: 19658829ms - 19658820ms =    9ms,  mp2dec delay     9ms
> PTSDIFF stc-pts: 19658992ms - 19658988ms =    4ms,  mp2dec delay     4ms

You will not hear/see a difference without comparison (your test
above with the echo effect).


         Werner
/*
 * xlist.c:	List the content of MPEG files
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
 *
 * Copyright (C) 2003 Werner Fink, <werner@suse.de>
 *
 * Partly based on ftp://ftp.cadsoft.de/vdr/xlist.c
 * Copyright (C) 2001 Klaus Schmidinger, <kls@cadsoft.de>
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <netinet/in.h>

#ifndef AARONS_TYPES
#define AARONS_TYPES
typedef unsigned long long uint_64;
typedef unsigned int   uint_32;
typedef unsigned short uint_16;
typedef unsigned char  uint_8;

typedef signed long long sint_64;
typedef signed int     sint_32;
typedef signed short   sint_16;
typedef signed char    sint_8;
#endif

#define dsyslog(format, args...)	fprintf(stderr, "xlist: " format "\n\r", ## args)
#define O_PIPE				(O_NONBLOCK|O_ASYNC)

// Exeption class
class cExeption {
public:
    const int reason;
    cExeption(const int Reason) : reason(Reason) {};
};

class cHandle {
private:
    uint_64 offset;
    uint_8 *const data;
    uint_8 * curr;
    const size_t size;
    const size_t over;
    volatile size_t left;
    volatile size_t head;
    volatile size_t tail;
    volatile size_t avail;
    int fd;
    cExeption ex;
    inline bool watch(unsigned long int ms)
    {
	fd_set watch;
	suseconds_t usec = ms*1000;
	struct timeval tv = { 0, usec};

	FD_ZERO(&watch);
	FD_SET(fd, &watch);

	int ret = 0;
	do {
	    errno = 0;
	    ret = select(fd+1, &watch, (fd_set*)0, (fd_set*)0, &tv);
	} while (ret < 0 && errno == EINTR);

	if (tv.tv_usec == usec)
	    ret = -1;
	return (ret > 0) ? FD_ISSET(fd, &watch) : false;
    }
    void refill(void) throw(cExeption)
    {
	size_t free;

	if (fd < 0)		// Static buffer, skip
	    goto out;

	if (!(free = (size - avail)))
	    goto out;

	do {
	    size_t  put = (tail+free > size) ? size - tail : free;
	    ssize_t real = read(fd, data+tail, put);
	    if (real < 0) {
		if (errno == EINTR || errno == EAGAIN)
		    continue;
		throw ex;
	    }
	    if (real == 0) {
		if (watch(320))
		    continue;
		fd = -1;	// Nothing new, we now have a static buffer
		break;
	    }
	    avail += real;
	    free  -= real;
	    tail   = (tail + real) % size;

	} while (free);
    out:
	return;
    };
    inline void rolling(const size_t pos)
    {
	ssize_t roll;
	//
	// Case of rolling the memory window over the end of the ring
	// buffer, just copy the data from the buffer begin to the
	// overroll area to get one continues memory window.
	//
	if ((pos < size) && ((roll = (pos+over) - size) > 0))
	    memcpy(data+size, data, roll);
    }
    inline void movwin(const size_t len)
    {
	size_t  want, pos = head;

	if (!len || (over && (len > over)))
	    goto out;

	if ((fd >= 0) && (avail < size/2))
	    (void)refill();

	if (avail == 0)
	    goto out;

	if ((want = len) > avail)
	    want = avail;

	pos += want;
	if (over)
	    rolling(pos);

	head = pos % size;
	curr = data+head;
	avail -= want;
	offset += want;
    out:
	return;
    };
    inline bool check(const size_t off) throw(cExeption)
    {
	if ((fd >= 0) && (avail < size/2))
	    (void)refill();
	left = avail;
	if (over) {
	    if (left > over)
		left = over;
	    rolling(head+off);
	}
	if (left < off)
	    throw ex;
	return true;
    }
public:
	//
	// Dynamic buffers filled from file opened with descriptor `file'
	// or static buffer aready filled.  In case of a dynamic filter
	// you may provide a minimal memory window step size to be able
	// to ensure continues buffers from operators even if a buffer
	// boundary is reached.
	//
    cHandle(uint_8 *buf, size_t len, const size_t step = 0, const int file = -1)
    : data(buf), curr(data), size(len-step), over(step), fd(file), ex(1)
    {
	avail = head = tail = 0;
	offset = 0;
	if (fd < 0) {		// For static buffers we assume a filled buffer
	    tail  += size;
	    avail += size;
	} else
	    (void)refill();
    };
	//
	// Return current offset
	//
    virtual const uint_64 Offset() const { return offset; };
	//
	// Return unsigned character value of
	// current buffer position
	//
    inline operator uint_8  () { return check(1) ? *curr : 0; };
	//
	// Return unsigned short value of current
	// buffer position (in big endian order)
	//
    inline operator uint_16 () { return check(2) ? ntohs(*((uint_16*)curr)) : 0; };
	//
	// Return unsigned int value of current
	// buffer position (in big endian order)
	//
    inline operator uint_32 () { return check(4) ? ntohl(*((uint_32*)curr)) : 0; };
	//
	// Returns true if buffer has at least one
	// left member
	//
    inline operator bool    () { return check(1); };
	//
	// A few useful relational operators
	//
    inline bool operator >= (const size_t&  o) { return		 (avail >= o); };
    inline bool operator >= (const ssize_t& o) { return ((ssize_t)avail >= o); };
    inline bool operator >  (const size_t&  o) { return		 (avail >  o); };
    inline bool operator >  (const ssize_t& o) { return ((ssize_t)avail >  o); };
    inline bool operator <= (const size_t&  o) { return		 (avail <= o); };
    inline bool operator <= (const ssize_t& o) { return ((ssize_t)avail <= o); };
    inline bool operator <  (const size_t&  o) { return		 (avail <  o); };
    inline bool operator <  (const ssize_t& o) { return ((ssize_t)avail <  o); };
    inline bool operator == (const size_t&  o) { return		 (avail == o); };
    inline bool operator == (const ssize_t& o) { return ((ssize_t)avail == o); };
    inline bool operator != (const size_t&  o) { return		 (avail != o); };
    inline bool operator != (const ssize_t& o) { return ((ssize_t)avail != o); };
	//
	// Skip current read position, goto next (++x).
	//
    inline cHandle& operator ++()      { movwin(1); return *this; };
	//
	// Skip current read position, goto next.
	// Return previous (x++).
	//
    inline cHandle  operator ++(int)
    {
	check(1);		// Before moving position, check and maybe rolling over
	const cHandle ret(*this); movwin(1); return ret;
    };
	//
	// Skip o positions from current read
	// position (x += o).
	//
    inline cHandle& operator +=(const size_t& o) { movwin(o); return *this; };
	//
	// Return current buffer position with at least
	// o members included. Do not use any position
	// operator during usage of the pointer to this
	// buffer position
	//
    inline uint_8*  operator ()(const size_t& o) { return check(o) ? curr : NULL; }
	//
	// Return left members of buffer. Should be less or
	// equal to step size if step size is larger than zero.
	//
    inline const size_t len(void) { check(0); return left; };
	//
	// Exeption handling: you should use this instead
	// of `while (handle)' or `if (handle)' ... this
	// avoids checks for potential buffer shortage.
	//
#   define foreach(handle)	try { while ((handle))
#   define test(handle)		try { if((handle))
#   define end(handle)		} catch (cExeption& ex) { if (ex.reason != 1) throw; }

};

// Signal handling
static struct sigaction saved_act[SIGUNUSED];
static void sighandler(int sig)
{
    sigset_t set;

    if (sig != SIGPIPE && sig != SIGIO)
	dsyslog("Catch %s", strsignal(sig));

    if (sig == SIGIO)
	return;

    usleep(100);

    if (sigaction (sig, &saved_act[sig], NULL))
	_exit(1);
    if (sigemptyset(&set) || sigaddset(&set, sig) ||
	sigprocmask(SIG_UNBLOCK, &set, NULL))
	_exit(1);
    kill(-getpid(), sig);	// Raise signal
}

static void install_sighandler(int sig)
{
    struct sigaction act;
    if (sigaction (sig, NULL, &saved_act[sig]))		// Old action handler
	return;
    if (saved_act[sig].sa_handler == sighandler)	// Compare with our
	return;

    act.sa_handler = sighandler;
    if (sig == SIGIO) {
	act.sa_flags = SA_RESTART;
    } else {
	act.sa_flags = SA_ONESHOT;
    }
    if (sigemptyset (&act.sa_mask) < 0)
	_exit(1);
    if (sigaction (sig, &act, NULL))
	_exit(1);
}

// Known options
static FILE* out = stdout;
#define D(format, args...)		fprintf(out, format "\n", ## args)
#define N(format, args...)		fprintf(out, format,      ## args)
#define nl				putc('\n', out);
static struct option long_option[] =
{
    {"help",      0, NULL,  'h'},
    {"block",     0, NULL,  'b'},
    {"output",    1, NULL,  'o'},
    {"noslices",  1, NULL,  's'},
    {"nobdpay",   1, NULL,  'd'},
    { NULL,       0, NULL,   0 },
};

static void help(void)
{
        printf("Usage: xlist <options> [file]\n");
        printf("\nAvailable options:\n");
        printf("  -h, --help         this help\n");
        printf("  -b, --block        use blocking read mode on stdin\n");
        printf("  -o, --output=file  use this file for output\n");
        printf("  -s, --noslices     do not show video slice nor sequences\n");
        printf("  -d, --nobdpay      do not show payload of private stream 1\n");
}

// Forward declaration
static bool skip_slices = false;
static bool skip_bdpayl = false;
static void scan(cHandle handle);

int main(int argc, char *argv[])
{
    bool block = false;
    cHandle *handle;
    char *output;
    int c;

    while ((c = getopt_long(argc, argv, "bo:hsd", long_option, NULL)) > 0) {
	switch (c) {
	case 'b':
	    block = true;
	    break;
	case 'o':
	    if (!optarg || *optarg == '-') {
		help();
		exit(1);
	    }
	    if (!(output = strdup(optarg))) {
		dsyslog("strdup() failed: %s", strerror(errno));
		exit(1);
	    }
	    if (!(out = fopen(output, "a+"))) {
		dsyslog("fopen(%s) failed: %s", output, strerror(errno));
		exit(1);
	    }
	    break;
	case 'h':
	    help();
	    exit(0);
	    break;
	case 's':
	    skip_slices = true;
	    break;
	case 'd':
	    skip_bdpayl = true;
	    break;
	default:
	    help();
	    exit(1);
	    break;
	}
    }
    argv += optind;
    argc -= optind;

    if (*argv && **argv == '-') {
	argv++;
	argc--;
    }

    install_sighandler(SIGINT);
    install_sighandler(SIGQUIT);
    install_sighandler(SIGHUP);
    install_sighandler(SIGTERM);
    install_sighandler(SIGPIPE);
    install_sighandler(SIGIO);

#   define STEPSIZE	 4096
#   define OVERALL	(128*STEPSIZE)
    static uint_8* buf = (uint_8*)malloc(OVERALL);

    if (!buf)
	exit(1);

    bool loop = true;
    while (true) {
	int fd = STDIN_FILENO;

	if (argc <= 0) {
	    if (!loop)
		break;
	    if (!block && fd == STDIN_FILENO) {
		int flags = fcntl(fd, F_GETFL);
		if (flags >= 0) {
		    if (fcntl(fd, F_SETFL, (flags|O_PIPE)) < 0 ||
			fcntl(fd, F_SETOWN, getpid()) < 0)
			dsyslog("Couldn't set NONBLOCK|ASYNC mode on stdin: %s", strerror(errno));
		}
	    }
	} else {
	    if (!*argv)
		break;
	    if ((fd = open(*argv, O_NOCTTY|O_RDONLY)) < 0) {
		dsyslog("Couldn't open file %s: %s", *argv, strerror(errno));
		exit(1);
	    }
	    argv++;
	    argc--;
	}
	loop = false;

	handle = new cHandle(&buf[0], OVERALL, STEPSIZE, fd);

	scan(*handle);

	if (handle) {
	    delete handle;
	    handle = NULL;
	}

	if (fd != STDIN_FILENO)
	    close (fd);
    }

    free(buf);
    return 0;
}

// Used in scan for video data
static off_t scan_e0(uint_8* const buf, const off_t rest, const uint_64 deep);

// Used in scan for private stream data
#define BD_IS_ALIGNED	0x01
#define BD_HAS_PTSDTS	0x02
static off_t scan_bd(uint_8* const buf, const off_t rest, const uint_8 flags, const uint_64 deep);


static void scan(cHandle handle)
{
    char I_Frame = 0; 
    bool Header  = false;

    foreach(handle >= 4) {
	uint_32 ul = handle;
	if ((ul & 0xffffff00) == 0x0000100) {
	    uint_64 offset = handle.Offset();
	    handle += 4;

	    uint_8  ub = (uint_8)(ul & 0x000000ff);
	    uint_16 m  = handle;
	    uint_8  l  = (uint_8)((m>>8)&0x00ff);

	    N("%8llu %02X", offset, ub);
	    switch (ub) {
	    case 0xb9:		// Program end (terminates a program stream)
		D(" program_end");
		break;
	    case 0xba:		// Pack header
		if (((l>>2) & 0x01) != 1 && (l>>6) != 1)
		    break;
		Header = true;
		I_Frame = 0;
		N(" pack_header");
		for (int i = 0; i < 10; i++)
		     N(" %02x", (uint_8)handle++);
		nl;
		break;
	    case 0xbb:		// System Header
		handle += 2;
		N(" system_header");
		N(", len=%d", m+6);
		N(", ext:");
		for (int i = 0; i < m && i < 20; i++)
		     N(" %02x", (uint_8)handle++);
		nl;
		break;
	    case 0xbc:		// Program Stream Map
		D(" program_stream_map");
		break;
	    case 0xbd:		// Private stream 1
		handle += 2;
		N(" private_stream_1");
		N(", len=%d", m+6);
		{
		    uint_8 *p;
		    uint_8  h;
		    uint_8  b = 0;
		    uint_16 l = m;

		    if (m < 2)
			break;
		    if (m > handle.len())
			m = handle.len();
		    if (!(p = handle(m)))
			break;
		    if (m < (h = p[2] + 3))
			break;
		    l -= h;

		    if ((p[0] & 0xC0) != 0x80) {
			N(" (broken)");
			break;
		    }

		    if (p[0]&0x04)
			b |= BD_IS_ALIGNED;
		    if (p[1] & 0xC0)
			b |= BD_IS_ALIGNED;

		    off_t off;
		    N(", ext:");
		    for (off = 0; off < h; off++)
			N(" %02x", p[off]);

		    if ((p[1] & 0x80) && (p[2] >= 5)) {
			static uint_64 lpts = 0;
			uint_64 pts = 0;
			pts  = (((uint_64)p[3]) & 0x0e) << 29;
			pts |= ( (uint_64)p[4])         << 22;
			pts |= (((uint_64)p[5]) & 0xfe) << 14;
			pts |= ( (uint_64)p[6])         <<  7;
			pts |= (((uint_64)p[7]) & 0xfe) >>  1;
			if (lpts) {
			    sint_64 diff = pts - lpts;
			    N(", pts: %llu          %lld", pts, diff);
			    if (diff > 0)
				lpts = pts;
			} else {
			    N(", pts: %llu", pts);
			    lpts = pts;
			}
		    }

		    if (skip_bdpayl)
			handle += m;
		    else
			handle += off + scan_bd(p+off, m-off, b, handle.Offset()+off);
		}
		nl;
		break;
	    case 0xbe:		// Padding stream
		handle += 2;
		l = handle;
		if (l != 0xff)
		    break;
		handle += m;
		D(" padding_stream, len=%d", m+6);
		break;
	    case 0xbf:		// Private stream 2
		handle += (2+m);
		D(" private_stream_2, len=%d", m+6);
		break;
	    case 0xc0 ... 0xdf:	// MPEG-1 or MPEG-2 audio stream
		handle += 2;
		N(" audio_stream(%d)", (ub & 0x1f));
		N(", len=%d", m+6);
		{
		    uint_8  *p;
		    uint_8  h;

		    if (m < 2)
			break;
		    if (m > handle.len())
			m = handle.len();
		    if (!(p = handle(m)))
			break;
		    if (m < (h = p[2] + 3))
			break;

		    if ((p[0] & 0xC0) != 0x80) {
			N(" (broken)");
			break;
		    }

		    off_t off;
		    N(", ext:");
		    for (off = 0; off < h; off++)
			N(" %02x", p[off]);

		    if ((p[1] & 0x80) && (p[2] >= 5)) {
			static uint_64 lpts = 0;
			uint_64 pts = 0;
			pts  = (((uint_64)p[3]) & 0x0e) << 29;
			pts |= ( (uint_64)p[4])         << 22;
			pts |= (((uint_64)p[5]) & 0xfe) << 14;
			pts |= ( (uint_64)p[6])         <<  7;
			pts |= (((uint_64)p[7]) & 0xfe) >>  1;
			if (lpts) {
			    sint_64 diff = pts - lpts;
			    N(", pts: %llu          %lld", pts, diff);
			    if (diff > 0)
				lpts = pts;
			} else {
			    N(", pts: %llu", pts);
			    lpts = pts;
			}
		    }

		    handle += m;
		}
		nl;
		break;
	    case 0xe0 ... 0xef:	// MPEG-1 or MPEG-2 video stream
		handle += 2;
		N(" video_stream(%d)", (ub & 0x0f));
		N(", len=%d", m+6);
		{
		    uint_8 *p;
		    uint_8 h;

		    if (m < 2)
			break;
		    if (m > handle.len())
			m = handle.len();
		    if (!(p = handle(m)))
			break;
		    if (m < (h = p[2] + 3))
			break;

		    if ((p[0] & 0xC0) != 0x80) {
			N(" (broken)");
			break;
		    }

		    off_t off;
		    N(", ext:");
		    for (off = 0; off < h; off++)
			N(" %02x", p[off]);

		    if ((p[1] & 0x80) && (p[2] >= 5)) {
			static uint_64 lpts = 0;
			uint_64 pts = 0;
			pts  = (((uint_64)p[3]) & 0x0e) << 29;
			pts |= ( (uint_64)p[4])         << 22;
			pts |= (((uint_64)p[5]) & 0xfe) << 14;
			pts |= ( (uint_64)p[6])         <<  7;
			pts |= (((uint_64)p[7]) & 0xfe) >>  1;
			if (lpts) {
			    sint_64 diff = pts - lpts;
			    N(", pts: %llu          %lld", pts, diff);
			    if (diff > 0)
				lpts = pts;
			} else {
			    N(", pts: %llu", pts);
			    lpts = pts;
			}
		    }

		    if (skip_slices)
			handle += m;
		    else
			handle += off + scan_e0(p+off, m-off, handle.Offset()+off);
		}
		nl;
		break;
	    case 0xf0:		// ECM Stream
		D(" ECM Stream");
		break;
	    case 0xf1:		// EMM Stream
		D(" EMM Stream");
		break;
	    case 0xf2:		// ITU-T Rec. H.222.0
				// ISO/IEC 13818-1 Annex A or ISO/IEC 13818-6 DSMCC stream
		D(" ITU-T Rec. H.222.0 | ISO/IEC 13818-1 | ISO/IEC 13818-6 DSMCC");
		break;
	    case 0xf3:		// ISO/IEC_13522_stream
		D(" ISO/IEC_13522_stream");
		break;
	    case 0xf4:		// ITU-T Rec. H.222.1 type A
		D(" ITU-T Rec. H.222.1 type A");
		break;
	    case 0xf5:		// ITU-T Rec. H.222.1 type B
		D(" ITU-T Rec. H.222.1 type B");
		break;
	    case 0xf6:		// ITU-T Rec. H.222.1 type C
		D(" ITU-T Rec. H.222.1 type C");
		break;
	    case 0xf7:		// ITU-T Rec. H.222.1 type D
		D(" ITU-T Rec. H.222.1 type D");
		break;
	    case 0xf8:		// ITU-T Rec. H.222.1 type E
		D(" ITU-T Rec. H.222.1 type E");
		break;
	    case 0xf9:		// ancillary_stream
		D(" ancillary_stream");
		break;
	    case 0xff:		// Program Stream Directory
		D(" program_stream_directory");
		break;
	    default:
		D(" unkown or reserved %08x", ul);
		break;
	    }
	} else {
	    handle++;
	}
    } end (handle);
};

static off_t scan_e0(uint_8* const buf, const off_t rest, const uint_64 deep)
{
    cHandle handle(buf, rest);
    char I_Frame = 0; 

    foreach(handle >= 4) {
	uint_32 ul = handle;
	if ((ul & 0xffffff00) == 0x0000100) {
	    uint_64 offset = handle.Offset() + deep;
	    handle += 4;

	    uint_8  ub = (uint_8)(ul & 0x000000ff);
	    uint_32 n  = handle;
	    uint_16 m  = (uint_16)((n>>16)&0x0000ffff);
	    uint_8  l  = (uint_8) ((m>> 8)&0x00ff);

	    nl;
	    N("%8llu %02X", offset, ub);
	    switch (ub) {
	    case 0x00:		// Picture
		handle += 4;
		switch ((m>>3)&0x07) {
		case 1:  I_Frame = 'I'; break;
		case 2:  I_Frame = 'P'; break;
		case 3:  I_Frame = 'B'; break;
		case 4:  I_Frame = 'D'; break;
		default: I_Frame =  0 ; break;
		}
		N(" picture_header - temporal_reference: %4d  picture_coding_type: %c", m>>6 , I_Frame);
		break;
	    case 0x01 ... 0xaf:
		N(" slice");
		for (int i = 0; i < 20; i++) {
		    uint_32 n = handle;
		    if ((n & 0xffffff00) == 0x0000100 && n != ul)
			break;
		    N(" %02x", (uint_8)handle++);
		}
		break;
	    case 0xb2:		// User data
		N(" user_data_start");
		break;
	    case 0xb3:		// Sequence header
		handle += 11;
		N(" sequence_header");
		break;
	    case 0xb4:		// Sequence error
		N(" sequence_error");
		break;
	    case 0xb5:		// Extension
		N(" extension_start");
		switch (l>>4) {
		case 1:
		    N(" (sequence_extension)");
		    handle +=  6;
		    break;
		case 2:
		    N(" (sequence_display_extension)");
		    handle++;
		    l = handle;	
		    if (l & 1)
			handle += 7;
		    else
			handle += 4;
		    break;
		case 8:
		    N(" (picture_coding_extension)");
		    handle += 4;
		    l = handle;
		    if (l & 0x40)
			handle += 3;
		    else
			handle++;
		    break;
		default:
		    break;
		}
		break;
	    case 0xb7:		// Sequence end
		N(" sequence_end");
		break;
	    case 0xb8:		// Group of Pictures
		N(" group_of_pictures_header - time_code:");
		N(" %02u:%02u:%02u.%02u", (n>>26)&0x1f, (n>>20)&0x3f, (n>>13)&0x3f, (n>>7)&0x3f);
		N(" closed_gop: %d broken_link: %d", (n>>6)&0x01, (n>>5)&0x01);
		break;
	    default:
		N(" unkown or reserved %08x", ul);
		break;
	    }
	} else {
	    handle++;
	}
    } end (handle);
    return rest;
}

static off_t scan_bd(uint_8* const buf, const off_t rest, const uint_8 flags, const uint_64 deep)
{
    cHandle handle(buf, rest);
    bool substream = false;

    test(handle >= 4) {
	uint_32 ul = handle;
	uint_8  ub = (uint_8) (ul>>24);

	uint_8 c = (uint_8)((ul>> 16)&0x00ff);
	off_t  o = (off_t)(ul & 0x0000ffff) + 3;

	uint_16 m;
	uint_32 n;

	switch (ub) {
	case 0x20 ... 0x3f:	// Subpictures
	    handle++;
	    {
		static sint_32 len = 0;
		if (!flags && !len)
		    break;
		if (flags) {
		    substream = true;
		    len = (uint_16)handle;
		    nl;
		    N("%8llu %02X", deep+handle.Offset()-1, (ub & 0xf8));
		    N(" substream(subpicture), len=%d spuh:", len);
		    for (int i = 0; i < 4; i++)
			 N(" %02x", (uint_8)handle++);
		    len -= (rest - 1);
		} else if (len) {
		    substream = true;
		    nl;
		    N("%8llu %02X", deep+handle.Offset()-1, (ub & 0xf8));
		    N(" substream(subpicture), rest=%d", len);
		    if ((len -= (rest - 1)) < 0)
			len = 0;
		}
	    }
	    break;
	case 0x80 ... 0x87:	// Dolby Digital Audio
	    if (o >= rest)
		break;
	    handle += o;
	    m = handle;
	    if (m == 0x0b77) {
		substream = true;
		nl;
		N("%8llu %02X", deep+handle.Offset()-o, (ub & 0xf8));
		N(" substream(AC3), stream: %u, count: %u, start: %lu", (ub & 7), c, o - 3);
	    }
	    break;
	case 0x88 ... 0x8f:	// DTS Audio
	    if (o+2 >= rest)
		break;
	    handle += o;
	    n = handle;
	    if (n == 0x7ffe8001) {
		substream = true;
		nl;
		N("%8llu %02X", deep+handle.Offset()-o, (ub & 0xf8));
		N(" substream(DTS), stream: %u, count: %u, start: %lu", (ub & 7), c, o - 3);
	    }
	    break;
	case 0xa0 ... 0xa7:	// Linear PCM Audio
	    if (o == 3)
		o = 7;
	    if (o >= rest)
		break;
	    {
		static sint_32 len = 0;
		if (!flags && !len)
		    break;
		if (flags) {
		    substream = true;
		    len = (rest - o);
		    nl;
		    N("%8llu %02X", deep+handle.Offset(), (ub & 0xf8));
		    N(" substream(PCM), len=%d, flags:", len);
		    handle += 3;
		    for (int i = 0; i < 3; i++)
			 N(" %02x", (uint_8)handle++);
		} else if (len) {
		    substream = true;
		    len = (rest - o);
		    nl;
		    N("%8llu %02X", deep+handle.Offset(), (ub & 0xf8));
		    N(" substream(PCM), rest=%d, flags", len);
		    handle += 3;
		    for (int i = 0; i < 3; i++)
			 N(" %02x", (uint_8)handle++);
		}
	    }
	    break;
	default:
	    break;
	}
    } end (handle);

    if (!substream) {
	cHandle handle(buf, rest);
	typedef struct _frmsize
	{
	    uint_16 bit_rate;
	    uint_16 frame_size[3];
	} frmsize_t;

	static const frmsize_t frmsizecod_tbl[64] = {
	    { 32  ,{64   ,69   ,96   } }, { 32  ,{64   ,70   ,96   } },
	    { 40  ,{80   ,87   ,120  } }, { 40  ,{80   ,88   ,120  } },
	    { 48  ,{96   ,104  ,144  } }, { 48  ,{96   ,105  ,144  } },
	    { 56  ,{112  ,121  ,168  } }, { 56  ,{112  ,122  ,168  } },
	    { 64  ,{128  ,139  ,192  } }, { 64  ,{128  ,140  ,192  } },
	    { 80  ,{160  ,174  ,240  } }, { 80  ,{160  ,175  ,240  } },
	    { 96  ,{192  ,208  ,288  } }, { 96  ,{192  ,209  ,288  } },
	    { 112 ,{224  ,243  ,336  } }, { 112 ,{224  ,244  ,336  } },
	    { 128 ,{256  ,278  ,384  } }, { 128 ,{256  ,279  ,384  } },
	    { 160 ,{320  ,348  ,480  } }, { 160 ,{320  ,349  ,480  } },
	    { 192 ,{384  ,417  ,576  } }, { 192 ,{384  ,418  ,576  } },
	    { 224 ,{448  ,487  ,672  } }, { 224 ,{448  ,488  ,672  } },
	    { 256 ,{512  ,557  ,768  } }, { 256 ,{512  ,558  ,768  } },
	    { 320 ,{640  ,696  ,960  } }, { 320 ,{640  ,697  ,960  } },
	    { 384 ,{768  ,835  ,1152 } }, { 384 ,{768  ,836  ,1152 } },
	    { 448 ,{896  ,975  ,1344 } }, { 448 ,{896  ,976  ,1344 } },
	    { 512 ,{1024 ,1114 ,1536 } }, { 512 ,{1024 ,1115 ,1536 } },
	    { 576 ,{1152 ,1253 ,1728 } }, { 576 ,{1152 ,1254 ,1728 } },
	    { 640 ,{1280 ,1393 ,1920 } }, { 640 ,{1280 ,1394 ,1920 } }
	};

	test(handle >= 4) {
	    static sint_32 len = 0;
	    sint_32 l = rest;
	    uint_16 m;
	    if (flags || len) {
		if (flags)
		    len = 0;		// On boundary normally AC3 starts
		if (len) {
		    nl;			// If not on boundary a overroll may occured
		    N("%8llu   ", deep+handle.Offset());
		    N(" plain(AC3) rest=%d", len);
		    handle += len;
		    l -= len;
		}
		while (l > 0) {
		    m = handle;
		    if (m == 0x0b77) {
			uint_16 fscod, frmsizecod;
			handle += 4;

			fscod	   = (((uint_8)handle)>>6)&3;
			frmsizecod =  ((uint_8)handle)&0x3f;
			len = 2*frmsizecod_tbl[frmsizecod].frame_size[fscod];

			nl;
			N("%8llu 0B", deep+handle.Offset()-4);
			N(" plain(AC3) size=%d", len);
			if (l < len) {
			    N(" included=%u", l);
			    len -= l;
			    break;
			}
			l -= len;
			handle += (len - 4);
		    } else {
			len = 0;
			break;
		    }
		}
	    }
	} end (handle);
    }

    return rest;
}

Home | Main Index | Thread Index