mirror of
https://github.com/outbackdingo/UltraGrid.git
synced 2026-03-21 15:40:21 +00:00
260 lines
6.9 KiB
C
260 lines
6.9 KiB
C
/* mknull.c
|
|
*
|
|
* MPEG-2 transport stream generation utility.
|
|
*
|
|
* Copyright (C) 2001-2006 Linear Systems Ltd. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of Linear Systems Ltd. nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY LINEAR SYSTEMS LTD. "AS IS" AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL LINEAR SYSTEMS LTD. OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
|
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* Linear Systems can be contacted at <http://www.linsys.ca/>.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "master.h"
|
|
|
|
/* This must be a multiple of 16 */
|
|
#define BUFFERED_PACKETS 16
|
|
|
|
static const char progname[] = "mknull";
|
|
|
|
/**
|
|
* Update the timestamps prepended to a number of packets
|
|
* based on an initial value, a running sum,
|
|
* the desired bitrate, and the packet size.
|
|
**/
|
|
static void
|
|
update_timestamps (unsigned char *p,
|
|
unsigned long long int *timestamp,
|
|
unsigned long long int *sum,
|
|
unsigned long long int bitrate,
|
|
int packetsize)
|
|
{
|
|
const unsigned long long int n = bitrate;
|
|
const unsigned long long int d = 216000000ULL;
|
|
const unsigned long long int ip = d * packetsize / n;
|
|
int i;
|
|
uint64_t *ts = (uint64_t *)p;
|
|
|
|
for (i = 0; i < BUFFERED_PACKETS; i++) {
|
|
*ts = *timestamp;
|
|
p += sizeof (uint64_t) + packetsize;
|
|
ts = (uint64_t *)p;
|
|
*sum += ip * n;
|
|
*timestamp += ip;
|
|
while (*sum < (d * packetsize)) {
|
|
*sum += n;
|
|
(*timestamp)++;
|
|
}
|
|
*sum -= d * packetsize;
|
|
}
|
|
return;
|
|
}
|
|
|
|
int
|
|
main (int argc, char **argv)
|
|
{
|
|
int opt, i, j, bufsize, retcode;
|
|
int bitrate, invert, packets, packetsize, tssize, packetnum, bytes;
|
|
unsigned char *data, *p;
|
|
char *endptr;
|
|
unsigned long long int timestamp, sum;
|
|
|
|
bitrate = 0;
|
|
invert = 0;
|
|
packets = -1; /* Generate an infinite number of packets */
|
|
packetsize = 188;
|
|
while ((opt = getopt (argc, argv, "b:hin:V2")) != -1) {
|
|
switch (opt) {
|
|
case 'b':
|
|
bitrate = strtol (optarg, &endptr, 0);
|
|
if ((*endptr != '\0') ||
|
|
(bitrate <= 0) || (bitrate > 216000000)) {
|
|
fprintf (stderr,
|
|
"%s: invalid bitrate: %s\n",
|
|
argv[0], optarg);
|
|
return -1;
|
|
}
|
|
break;
|
|
case 'h':
|
|
printf ("Usage: %s [OPTION]...\n", argv[0]);
|
|
printf ("Repeatedly output null "
|
|
"MPEG-2 transport stream packets\n"
|
|
"with an ascending continuity_counter "
|
|
"and a payload of 0xff.\n\n");
|
|
printf (" -b BITRATE\tprepend timestamps "
|
|
"at BITRATE bits per second\n");
|
|
printf (" -h\t\tdisplay this help and exit\n");
|
|
printf (" -i\t\tinvert every eighth "
|
|
"packet synchronization byte\n");
|
|
printf (" -n NUM\tstop after NUM packets\n");
|
|
printf (" -V\t\toutput version information "
|
|
"and exit\n");
|
|
printf (" -2\t\tappend sixteen 0x00 bytes "
|
|
"to each 188-byte packet\n");
|
|
printf ("\nReport bugs to <support@linsys.ca>.\n");
|
|
return 0;
|
|
case 'i':
|
|
invert = 1;
|
|
break;
|
|
case 'n':
|
|
packets = strtol (optarg, &endptr, 0);
|
|
if (*endptr != '\0') {
|
|
fprintf (stderr,
|
|
"%s: invalid number of packets: %s\n",
|
|
argv[0], optarg);
|
|
return -1;
|
|
}
|
|
break;
|
|
case 'V':
|
|
printf ("%s from master-%s (%s)\n", progname,
|
|
MASTER_DRIVER_VERSION,
|
|
MASTER_DRIVER_DATE);
|
|
printf ("\nCopyright (C) 2001-2006 "
|
|
"Linear Systems Ltd.\n"
|
|
"This is free software; "
|
|
"see the source for copying conditions. "
|
|
"There is NO\n"
|
|
"warranty; not even for MERCHANTABILITY "
|
|
"or FITNESS FOR A PARTICULAR PURPOSE.\n");
|
|
return 0;
|
|
case '2':
|
|
packetsize = 204;
|
|
break;
|
|
case '?':
|
|
goto USAGE;
|
|
}
|
|
}
|
|
|
|
/* Check the number of arguments */
|
|
if ((argc - optind) > 0) {
|
|
fprintf (stderr, "%s: extra operand\n", argv[0]);
|
|
goto USAGE;
|
|
}
|
|
|
|
/* Allocate a buffer */
|
|
tssize = (bitrate > 0) ? 8 : 0;
|
|
bufsize = BUFFERED_PACKETS * (packetsize + tssize);
|
|
if ((data = (unsigned char *)malloc (bufsize)) == NULL) {
|
|
fprintf (stderr, "%s: unable to allocate memory\n", argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
/* Initialize the buffer */
|
|
p = data;
|
|
packetnum = 0;
|
|
for (i = 0; i < BUFFERED_PACKETS; i++) {
|
|
if (bitrate > 0) {
|
|
p += 8;
|
|
}
|
|
if (invert) {
|
|
*p++ = (packetnum % 8) ? 0x47 : 0xB8;
|
|
} else {
|
|
*p++ = 0x47;
|
|
}
|
|
*p++ = 0x1f;
|
|
*p++ = 0xff;
|
|
*p++ = 0x10 | packetnum;
|
|
packetnum = (packetnum + 1) & 0x0f;
|
|
for (j = 4; j < 188; j++) {
|
|
*p++ = 0xff;
|
|
}
|
|
for (j = 188; j < packetsize; j++) {
|
|
*p++ = 0x00;
|
|
}
|
|
}
|
|
timestamp = 0ULL;
|
|
sum = 0ULL;
|
|
if (bitrate > 0) {
|
|
uint64_t *ts = (uint64_t *)data;
|
|
|
|
update_timestamps (data,
|
|
×tamp,
|
|
&sum,
|
|
bitrate,
|
|
packetsize);
|
|
*ts |= UINT64_C(0x8000000000000000);
|
|
}
|
|
|
|
/* Generate the data */
|
|
while (packets) {
|
|
bytes = 0;
|
|
if ((packets < BUFFERED_PACKETS) && (packets > 0)) {
|
|
/* The number of packets to write is less than
|
|
* the buffer size and is not infinite (-1). */
|
|
while (bytes < (packets * (packetsize + tssize))) {
|
|
if ((retcode = write (STDOUT_FILENO,
|
|
data + bytes,
|
|
(packets * (packetsize + tssize)) -
|
|
bytes)) < 0) {
|
|
fprintf (stderr, "%s: ", argv[0]);
|
|
perror ("unable to write to output");
|
|
free (data);
|
|
return -1;
|
|
}
|
|
bytes += retcode;
|
|
}
|
|
packets = 0;
|
|
} else {
|
|
/* The number of packets to write is greater than
|
|
* or equal to the buffer size or is infinite (-1). */
|
|
while (bytes < bufsize) {
|
|
if ((retcode = write (STDOUT_FILENO,
|
|
data + bytes, bufsize - bytes)) < 0) {
|
|
fprintf (stderr, "%s: ", argv[0]);
|
|
perror ("unable to write to output");
|
|
free (data);
|
|
return -1;
|
|
}
|
|
bytes += retcode;
|
|
}
|
|
if (packets > 0) {
|
|
packets -= BUFFERED_PACKETS;
|
|
}
|
|
if (bitrate > 0) {
|
|
update_timestamps (data,
|
|
×tamp,
|
|
&sum,
|
|
bitrate,
|
|
packetsize);
|
|
}
|
|
}
|
|
}
|
|
free (data);
|
|
return 0;
|
|
|
|
USAGE:
|
|
fprintf (stderr, "Try '%s -h' for more information.\n", argv[0]);
|
|
return -1;
|
|
}
|
|
|