Sync to FreeBSD.

Add fwmethods.h fwmpegts.c
  fwcontrol.c Rev.1.23
  fwctl.8 Rev.1.21
  fwdv.c Rev.1.7
Support MPEG2-TS/HDV.  But not tested.
This commit is contained in:
kiyohara 2007-11-06 17:02:15 +00:00
parent d880ffcdf0
commit 3caf19136d
6 changed files with 480 additions and 68 deletions

View File

@ -1,7 +1,7 @@
# $NetBSD: Makefile,v 1.1 2005/07/11 15:35:25 kiyohara Exp $
# $NetBSD: Makefile,v 1.2 2007/11/06 17:02:15 kiyohara Exp $
PROG= fwctl
SRCS= eui64.c fwcontrol.c fwcrom.c fwdv.c
SRCS= eui64.c fwcontrol.c fwcrom.c fwdv.c fwmpegts.c
MAN= fwctl.8
.PATH: ${.CURDIR}/../../sys/dev/ieee1394

View File

@ -1,8 +1,8 @@
/* $NetBSD: fwcontrol.c,v 1.5 2006/05/24 22:08:53 christos Exp $ */
/* $NetBSD: fwcontrol.c,v 1.6 2007/11/06 17:02:15 kiyohara Exp $ */
/*
* Copyright (C) 2002
* Hidetoshi Shimokawa. All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@ -19,7 +19,7 @@
* 4. Neither the name of the author 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 THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@ -35,7 +35,7 @@
#if defined(__FreeBSD__)
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: /repoman/r/ncvs/src/usr.sbin/fwcontrol/fwcontrol.c,v 1.22 2005/05/20 12:50:47 charnier Exp $");
__FBSDID("$FreeBSD: src/usr.sbin/fwcontrol/fwcontrol.c,v 1.23 2006/10/26 22:33:38 imp Exp $");
#endif
#include <sys/param.h>
@ -50,11 +50,13 @@ __FBSDID("$FreeBSD: /repoman/r/ncvs/src/usr.sbin/fwcontrol/fwcontrol.c,v 1.22 20
#include <dev/firewire/firewire.h>
#include <dev/firewire/iec13213.h>
#include <dev/firewire/fwphyreg.h>
#include <dev/firewire/iec68113.h>
#elif defined(__NetBSD__)
#include "eui64.h"
#include <dev/ieee1394/firewire.h>
#include <dev/ieee1394/iec13213.h>
#include <dev/ieee1394/fwphyreg.h>
#include <dev/ieee1394/iec68113.h>
#endif
#include <netinet/in.h>
@ -63,12 +65,11 @@ __FBSDID("$FreeBSD: /repoman/r/ncvs/src/usr.sbin/fwcontrol/fwcontrol.c,v 1.22 20
#include <err.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
#include "fwmethods.h"
extern int dvrecv(int, char *, char, int);
extern int dvsend(int, char *, char, int);
int sysctl_set_int(const char *, int);
static void sysctl_set_int(const char *, int);
static void
usage(void)
@ -87,13 +88,13 @@ usage(void)
"\t-m: set fwmem target\n"
"\t-o: send link-on packet to the node\n"
"\t-p: dump PHY registers\n"
"\t-R: receive DV stream\n"
"\t-R: receive DV or MPEG TS stream\n"
"\t-r: bus reset\n"
"\t-S: send DV stream\n"
"\t-s: write RESET_START register on the node\n"
"\t-t: read topology map\n"
"\t-u: specify bus number\n", getprogname());
exit(0);
exit(EX_USAGE);
}
static void
@ -297,7 +298,7 @@ reset_start(int fd, int node)
}
static void
set_pri_req(int fd, int pri_req)
set_pri_req(int fd, u_int32_t pri_req)
{
struct fw_devlstreq *data;
struct fw_devinfo *devinfo;
@ -317,7 +318,7 @@ set_pri_req(int fd, int pri_req)
eui64_ntoa(&eui, addr, sizeof(addr));
printf("%d %s, %08x",
devinfo->dst, addr, reg);
if (reg > 0 && pri_req >= 0) {
if (reg > 0) {
old = (reg & 0x3f);
max = (reg & 0x3f00) >> 8;
if (pri_req > max)
@ -332,7 +333,7 @@ set_pri_req(int fd, int pri_req)
}
static void
parse_bus_info_block(u_int32_t *p, int info_len)
parse_bus_info_block(u_int32_t *p)
{
char addr[EUI64_SIZ];
struct bus_info *bi;
@ -413,7 +414,7 @@ show_crom(u_int32_t *crom_buf)
printf("(OK)\n");
else
printf("(NG)\n");
parse_bus_info_block(crom_buf+1, hdr->info_len);
parse_bus_info_block(crom_buf+1);
crom_init_context(&cc, crom_buf);
dir = cc.stack[0].dir;
@ -568,7 +569,7 @@ dump_phy_registers(int fd)
"Max_Legacy_SPD:%d BLINK:%d Bridge:%d\n"
"Page_Select:%d Port_Select%d\n",
b.phy_id, b.r, b.cps,
b.rhb, b.ibr, b.gap_count,
b.rhb, b.ibr, b.gap_count,
b.extended, b.num_ports,
b.phy_speed, b.delay,
b.lctrl, b.c, b.jitter, b.pwr_class,
@ -625,12 +626,60 @@ open_dev(int *fd, char *devbase)
}
}
int
static void
sysctl_set_int(const char *name, int val)
{
if (sysctlbyname(name, NULL, NULL, &val, sizeof(int)) < 0)
err(1, "sysctl %s failed.", name);
return (0);
}
static fwmethod *
detect_recv_fn(int fd, char ich)
{
char *buf;
struct fw_isochreq isoreq;
struct fw_isobufreq bufreq;
int len;
u_int32_t *ptr;
struct ciphdr *ciph;
fwmethod *retfn;
bufreq.rx.nchunk = 8;
bufreq.rx.npacket = 16;
bufreq.rx.psize = 1024;
bufreq.tx.nchunk = 0;
bufreq.tx.npacket = 0;
bufreq.tx.psize = 0;
if (ioctl(fd, FW_SSTBUF, &bufreq) < 0)
err(1, "ioctl FW_SSTBUF");
isoreq.ch = ich & 0x3f;
isoreq.tag = (ich >> 6) & 3;
if (ioctl(fd, FW_SRSTREAM, &isoreq) < 0)
err(1, "ioctl FW_SRSTREAM");
buf = (char *)malloc(1024*16);
len = read(fd, buf, 1024*16);
ptr = (u_int32_t *) buf;
ciph = (struct ciphdr *)(ptr + 1);
switch(ciph->fmt) {
case CIP_FMT_DVCR:
fprintf(stderr, "Detected DV format on input.\n");
retfn = dvrecv;
break;
case CIP_FMT_MPEG:
fprintf(stderr, "Detected MPEG TS format on input.\n");
retfn = mpegtsrecv;
break;
default:
errx(1, "Unsupported format for receiving: fmt=0x%x",
ciph->fmt);
}
free(buf);
return retfn;
}
int
@ -638,9 +687,11 @@ main(int argc, char **argv)
{
u_int32_t crom_buf[1024/4];
char devbase[1024] = "/dev/fw0";
int fd, tmp, ch, len=1024;
int fd, ch, len=1024;
long tmp;
struct fw_eui64 eui;
struct eui64 target;
fwmethod *recvfn = NULL;
fd = -1;
@ -649,10 +700,12 @@ main(int argc, char **argv)
list_dev(fd);
}
while ((ch = getopt(argc, argv, "g:m:o:s:b:prtc:d:l:u:R:S:")) != -1)
while ((ch = getopt(argc, argv, "M:g:m:o:s:b:prtc:d:l:u:R:S:")) != -1)
switch(ch) {
case 'b':
tmp = strtol(optarg, NULL, 0);
if (tmp < 0 || tmp > (long)0xffffffff)
errx(EX_USAGE, "invalid number: %s", optarg);
open_dev(&fd, devbase);
set_pri_req(fd, tmp);
break;
@ -680,7 +733,7 @@ main(int argc, char **argv)
case 'm':
if (eui64_hostton(optarg, &target) != 0 &&
eui64_aton(optarg, &target) != 0)
errx(1, "invalid target: %s", optarg);
errx(EX_USAGE, "invalid target: %s", optarg);
eui.hi = ntohl(*(u_int32_t*)&(target.octet[0]));
eui.lo = ntohl(*(u_int32_t*)&(target.octet[4]));
sysctl_set_int("hw.fwmem.eui64_hi", eui.hi);
@ -711,7 +764,7 @@ main(int argc, char **argv)
break;
case 'u':
tmp = strtol(optarg, NULL, 0);
snprintf(devbase, sizeof(devbase), "/dev/fw%d", tmp);
snprintf(devbase, sizeof(devbase), "/dev/fw%ld", tmp);
if (fd > 0) {
close(fd);
fd = -1;
@ -723,9 +776,27 @@ main(int argc, char **argv)
break;
#define TAG (1<<6)
#define CHANNEL 63
case 'M':
switch (optarg[0]) {
case 'm':
recvfn = mpegtsrecv;
break;
case 'd':
recvfn = dvrecv;
break;
default:
errx(EX_USAGE, "unrecognized method: %s",
optarg);
}
break;
case 'R':
open_dev(&fd, devbase);
dvrecv(fd, optarg, TAG | CHANNEL, -1);
if (recvfn == NULL) /* guess... */
recvfn = detect_recv_fn(fd, TAG | CHANNEL);
close(fd);
fd = -1;
open_dev(&fd, devbase);
(*recvfn)(fd, optarg, TAG | CHANNEL, -1);
break;
case 'S':
open_dev(&fd, devbase);

View File

@ -1,4 +1,4 @@
.\" $NetBSD: fwctl.8,v 1.5 2007/03/05 04:56:48 xtraeme Exp $
.\" $NetBSD: fwctl.8,v 1.6 2007/11/06 17:02:15 kiyohara Exp $
.\"
.\" Copyright (c) 2005 KIYOHARA Takashi
.\" All rights reserved.
@ -27,9 +27,9 @@
.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $FreeBSD: /repoman/r/ncvs/src/usr.sbin/fwcontrol/fwcontrol.8,v 1.16 2005/01/18 20:02:34 ru Exp $
.\" $FreeBSD: src/usr.sbin/fwcontrol/fwcontrol.8,v 1.21 2007/10/31 05:59:17 brueffer Exp $
.\"
.Dd March 5, 2007
.Dd November 6, 2007
.Dt FWCTL 8
.Os
.Sh NAME
@ -43,6 +43,7 @@
.Op Fl d Ar node
.Op Fl g Ar gap_count
.Op Fl l Ar file
.Op Fl M Ar mode
.Op Fl m Ar EUI64 | hostname
.Op Fl o Ar node
.Op Fl R Ar filename
@ -76,6 +77,15 @@ Broadcast
by phy_config packet.
.It Fl l Ar file
Load hex dump file of the configuration ROM and parse it.
.It Fl M Ar modeExplicitly specify either
.Ar dv
or
.Ar mpeg
mode for the incoming stream.
Only meaningful in case of and must precede the
.Fl R
option. If not specified, the program will try to guess. If you get
an error complaining about "format 0x20", try to force the "mpeg" mode.
.It Fl m Ar EUI64 | hostname
Set default fwmem target.
Hostname will be converted to EUI64.
@ -84,7 +94,7 @@ Send a link-on PHY packet to the node.
.It Fl p
Dump PHY registers.
.It Fl R Ar filename
Receive DV stream and dump it to a file.
Receive DV or MPEG TS stream and dump it to a file.
Use Ctrl-C to stop the receiving.
Some DV cameras seem not to send the stream if a bus manager exits.
If you cannot get the stream, try the following commands:
@ -98,6 +108,14 @@ and CIP header.
It can be handled by the
.Pa pkgsrc/multimedia/libdv
package.
Resulting MPEG TS stream can be played and sent over a network using
the VideoLAN
.Nm vlc
tool in the
.Fx
Ports Collection. The stream can be piped directly to
.Nm vlc,
see EXAMPLES.
.It Fl r
Initiate bus reset.
.It Fl S Ar filename
@ -120,7 +138,7 @@ Each DV frame has a fixed size and it is easy to edit the frame order.
.Pp
.Dl "fwctl -R original.dv"
.Pp
Receive stream.
Receive a DV stream with DV camera attached.
.Pp
.Dl "dd if=original.dv of=first.dv bs=120000 count=30"
.Pp
@ -138,7 +156,37 @@ For PAL, replace
.Dq Li bs=120000
with
.Dq Li bs=144000 .
.Pp
.Dl "fwcontrol -R file.m2t
.Pp
Receive an MPEG TS stream from a camera producing MPEG transport stream. This
has been tested with SONY HDR-FX1E camera that produces HD MPEG-2 stream at
25 Mbps bandwidth.
.Pp
To send the stream from the camera over the network using TCP (which
supprisingly works better with vlc), you can use
.Dl "fwcontrol -R - | nc 192.168.10.11 9000
with
.Nm netcat
from ports and to receive the stream, use
.Dl nc -l -p 9000 | vlc -
.Pp
To netcast via UDP, you need to use
.Nm buffer
program from ports, since vlc is not fast enough to read UDP packets from
buffers and thus it experiences dropouts when run directly. The sending side
can use
.Dl "fwcontrol -R - | nc 192.168.10.11 9000
and to receive the stream, use
.Dl nc -l -u -p 9000 | buffer -s 10k -b 1000 -m 20m -p 5 | vlc -
.Pp
.Pp
For more information on how to work with
.Nm vlc
see its docs.
.Sh SEE ALSO
.Xr mplayer 1 ,
.Xr vlc 1 ,
.Xr fwip 4 ,
.Xr fwohci 4 ,
.Xr ieee1394if 4 ,
@ -155,7 +203,11 @@ It was added to
under its present name.
.Sh AUTHORS
.An Hidetoshi Shimokawa Aq simokawa@FreeBSD.org
.An Petr Holub Aq hopet@ics.muni.cz
- MPEG TS mode.
.An KIYOHARA Takashi Aq kiyohara@NetBSD.org
.Sh BUGS
This utility is still under development and provided for debugging
purposes.
Especially MPEG TS reception support is very rudimental and supports only
high-bandwidth MPEG-2 streams (fn field in CIP header equals 3).

View File

@ -1,8 +1,8 @@
/* $NetBSD: fwdv.c,v 1.1 2005/07/11 15:35:25 kiyohara Exp $ */
/* $NetBSD: fwdv.c,v 1.2 2007/11/06 17:02:15 kiyohara Exp $ */
/*
* Copyright (C) 2003
* Hidetoshi Shimokawa. All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@ -19,7 +19,7 @@
* 4. Neither the name of the author 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 THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@ -31,8 +31,8 @@
* 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.
*
* $FreeBSD: src/usr.sbin/fwcontrol/fwdv.c,v 1.5 2003/04/17 03:38:03 simokawa Exp $
*
* $FreeBSD: src/usr.sbin/fwcontrol/fwdv.c,v 1.7 2007/06/17 10:20:55 simokawa Exp $
*/
#include <sys/param.h>
#include <sys/ioctl.h>
@ -51,6 +51,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#if defined(__FreeBSD__)
#include <dev/firewire/firewire.h>
@ -60,14 +61,13 @@
#include <dev/ieee1394/iec68113.h>
#endif
int dvrecv(int, char *, char, int);
int dvsend(int, char *, char, int);
#include "fwmethods.h"
#define DEBUG 0
#define FIX_FRAME 1
struct frac {
int n,d;
int n,d;
};
struct frac frame_cycle[2] = {
@ -87,7 +87,7 @@ int frame_rate[] = {30, 25};
#define PSIZE 512
#define DSIZE 480
#define NCHUNK 8
#define NCHUNK 64
#define NPACKET_R 256
#define NPACKET_T 255
@ -97,8 +97,8 @@ int frame_rate[] = {30, 25};
#define MAXBLOCKS (300)
#define CYCLE_FRAC 0xc00
int
dvrecv(int d, char *filename, char ich, int count)
void
dvrecv(int d, const char *filename, char ich, int count)
{
struct fw_isochreq isoreq;
struct fw_isobufreq bufreq;
@ -111,9 +111,15 @@ dvrecv(int d, char *filename, char ich, int count)
int nblocks[] = {250 /* NTSC */, 300 /* PAL */};
struct iovec wbuf[NPACKET_R];
fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0660);
buf = (char *)malloc(RBUFSIZE);
pad = (char *)malloc(DSIZE*MAXBLOCKS);
if(strcmp(filename, "-") == 0) {
fd = STDOUT_FILENO;
} else {
fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0660);
if (fd == -1)
err(EX_NOINPUT, filename);
}
buf = malloc(RBUFSIZE);
pad = malloc(DSIZE*MAXBLOCKS);
memset(pad, 0xff, DSIZE*MAXBLOCKS);
bzero(wbuf, sizeof(wbuf));
@ -123,14 +129,13 @@ dvrecv(int d, char *filename, char ich, int count)
bufreq.tx.nchunk = 0;
bufreq.tx.npacket = 0;
bufreq.tx.psize = 0;
if (ioctl(d, FW_SSTBUF, &bufreq) < 0) {
err(1, "ioctl");
}
if (ioctl(d, FW_SSTBUF, &bufreq) < 0)
err(1, "ioctl FW_SSTBUF");
isoreq.ch = ich & 0x3f;
isoreq.tag = (ich >> 6) & 3;
if( ioctl(d, FW_SRSTREAM, &isoreq) < 0)
if (ioctl(d, FW_SRSTREAM, &isoreq) < 0)
err(1, "ioctl");
k = m = 0;
@ -141,7 +146,8 @@ dvrecv(int d, char *filename, char ich, int count)
/* RBUFSIZE - tlen */)) > 0) {
if (len < 0) {
if (errno == EAGAIN) {
fprintf(stderr, "(EAGAIN)\n");
fprintf(stderr,
"(EAGAIN)- push 'Play'?\n");
fflush(stderr);
if (len <= 0)
continue;
@ -167,7 +173,7 @@ dvrecv(int d, char *filename, char ich, int count)
vec = 0;
ptr = (u_int32_t *) buf;
again:
pkt = (struct fw_pkt *) ptr;
pkt = (struct fw_pkt *) ptr;
#if DEBUG
fprintf(stderr, "%08x %08x %08x %08x\n",
htonl(ptr[0]), htonl(ptr[1]),
@ -195,7 +201,8 @@ again:
if (dv->sct == DV_SCT_HEADER && dv->dseq == 0) {
if (system < 0) {
system = ciph->fdf.dv.fs;
printf("%s\n", system_name[system]);
fprintf(stderr,
"%s\n", system_name[system]);
}
/* Fix DSF bit */
@ -246,21 +253,22 @@ next:
if (vec > 0)
writev(fd, wbuf, vec);
}
close(fd);
if(fd != STDOUT_FILENO) {
close(fd);
}
fprintf(stderr, "\n");
return 0;
}
int
dvsend(int d, char *filename, char ich, int count)
void
dvsend(int d, const char *filename, char ich, int count)
{
struct fw_isochreq isoreq;
struct fw_isobufreq bufreq;
struct dvdbc *dv;
struct fw_pkt *pkt;
int len, tlen, header, fd, frames, packets, vec, offset, nhdr, i;
int system=-1, pad_acc, cycle_acc, cycle, f_cycle, f_frac;
int system=-1, pad_acc, cycle_acc, cycle, f_cycle, f_frac;
struct iovec wbuf[TNBUF*2 + NEMPTY];
char *pbuf;
u_int32_t iso_data, iso_empty, hdr[TNBUF + NEMPTY][3];
@ -271,7 +279,10 @@ dvsend(int d, char *filename, char ich, int count)
cycle_acc = cycle = 0;
fd = open(filename, O_RDONLY);
pbuf = (char *)malloc(DSIZE * TNBUF);
if (fd == -1)
err(EX_NOINPUT, filename);
pbuf = malloc(DSIZE * TNBUF);
bzero(wbuf, sizeof(wbuf));
bufreq.rx.nchunk = 0;
@ -280,15 +291,14 @@ dvsend(int d, char *filename, char ich, int count)
bufreq.tx.nchunk = NCHUNK;
bufreq.tx.npacket = NPACKET_T;
bufreq.tx.psize = PSIZE;
if (ioctl(d, FW_SSTBUF, &bufreq) < 0) {
err(1, "ioctl");
}
if (ioctl(d, FW_SSTBUF, &bufreq) < 0)
err(1, "ioctl FW_SSTBUF");
isoreq.ch = ich & 0x3f;
isoreq.tag = (ich >> 6) & 3;
if( ioctl(d, FW_STSTREAM, &isoreq) < 0)
err(1, "ioctl");
if (ioctl(d, FW_STSTREAM, &isoreq) < 0)
err(1, "ioctl FW_STSTREAM");
iso_data = 0;
pkt = (struct fw_pkt *) &iso_data;
@ -309,9 +319,8 @@ dvsend(int d, char *filename, char ich, int count)
ciph->eoh1 = 1;
ciph->fdf.dv.cyc = 0xffff;
for (i = 1; i < TNBUF; i++) {
for (i = 1; i < TNBUF; i++)
bcopy(hdr[0], hdr[i], sizeof(hdr[0]));
}
gettimeofday(&start, NULL);
#if DEBUG
@ -331,7 +340,7 @@ dvsend(int d, char *filename, char ich, int count)
if (len < 0)
warn("read");
else
printf("\nend of file\n");
fprintf(stderr, "\nend of file\n");
goto send_end;
}
tlen += len;
@ -402,8 +411,7 @@ again:
len = writev(d, wbuf, vec);
if (len < 0) {
if (errno == EAGAIN) {
fprintf(stderr, "(EAGAIN)\n");
fflush(stderr);
fprintf(stderr, "(EAGAIN) - push 'Play'?\n");
goto again;
}
err(1, "write failed");
@ -413,9 +421,8 @@ again:
fprintf(stderr, "\n");
send_end:
gettimeofday(&end, NULL);
rtime = end.tv_sec - start.tv_sec
rtime = end.tv_sec - start.tv_sec
+ (end.tv_usec - start.tv_usec) * 1e-6;
fprintf(stderr, "%d frames, %.2f secs, %.2f frames/sec\n",
frames, rtime, frames/rtime);
return 0;
}

View File

@ -0,0 +1,10 @@
/*-
* This file is in the public domain.
*
* $FreeBSD: src/usr.sbin/fwcontrol/fwmethods.h,v 1.1 2006/10/26 22:33:38 imp Exp $
*/
typedef void (fwmethod)(int dev_fd, const char *filename, char ich, int count);
extern fwmethod dvrecv;
extern fwmethod dvsend;
extern fwmethod mpegtsrecv;

272
usr.sbin/fwctl/fwmpegts.c Normal file
View File

@ -0,0 +1,272 @@
/*
* Copyright (C) 2005
* Petr Holub, Hidetoshi Shimokawa. 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by Hidetoshi Shimokawa.
*
* 4. Neither the name of the author 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS 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.
*
* $FreeBSD: src/usr.sbin/fwcontrol/fwmpegts.c,v 1.1 2006/10/26 22:33:38 imp Exp $
*/
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/uio.h>
#if __FreeBSD_version >= 500000
#include <arpa/inet.h>
#endif
#include <err.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#if defined(__FreeBSD__)
#include <dev/firewire/firewire.h>
#include <dev/firewire/iec68113.h>
#elif defined(__NetBSD__)
#include <dev/ieee1394/firewire.h>
#include <dev/ieee1394/iec68113.h>
#endif
#include "fwmethods.h"
#define DEBUG 0
/*****************************************************************************
MPEG-2 Transport Stream (MPEG TS) packet format according to IEC 61883:
31 15 0
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ --------
| len |tag| channel | tcode | sy |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1394
| header_CRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ --------
|0|0| sid | dbs |fn | qpc |S|RSV| dbc |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ CIP
|1|0| fmt | fdf | fdf/syt |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ --------
| reserved | cycle_count | cycle_offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | N x
. . MPEG
. MPEG TS payload 188 bytes .
. .
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ --------
| data_CRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
N.b. that CRCs are removed by firewire layer!
The following fiels are fixed for IEEE-1394:
tag = 01b
tcode = 1010b
The length is payload length, i.e. includes CIP header and data size.
The following fields are constant for MPEG TS:
sph = 1 (denoted as S in CIP header above)
dbs = 6
fmt = (1<<5)
fdf = reserved
In the supported streams we also require
qpc = 0
fn = 3
and thus the payload is divided in 8 blocks as follows:
+-----+-----+-----+-----+-----+-----+-----+-----+
| db0 | db1 | db2 | db3 | db4 | db5 | db6 | db7 |
+-----+-----+-----+-----+-----+-----+-----+-----+
We have several cases of payload distribution based on stream
bandwidth (R):
1) R < 1.5 Mbps: any of db0..db7 may be payload,
2) 1.5 < R < 3 Mbps: db0/db1 or db2/db3 or db4/db5 or db6/db7 is payload,
3) 3 < R < 6 Mbps: db0/db1/db2/db3 or db4/db5/db6/db7 is payload,
4) R > 6 Mbps: all db0..db7 contain the payload.
Curently, only case (4) is supported in fwmpegts.c
Each packet may contain N MPEG TS data blocks with timestamp header,
which are (4+188)B long. Experimentally, the N ranges from 0 through 3.
*****************************************************************************/
typedef uint8_t mpeg_ts_pld[188];
struct mpeg_pldt {
#if BYTE_ORDER == BIG_ENDIAN
uint32_t :7,
c_count:13,
c_offset:12;
#else /* BYTE_ORDER != BIG_ENDIAN */
uint32_t c_offset:12,
c_count:13,
:7;
#endif /* BYTE_ORDER == BIG_ENDIAN */
mpeg_ts_pld payload;
};
#define NCHUNK 8
#define PSIZE 596
#define NPACKET_R 4096
#define RBUFSIZE (PSIZE * NPACKET_R)
void
mpegtsrecv(int d, const char *filename, char ich, int count)
{
struct ciphdr *ciph;
struct fw_isochreq isoreq;
struct fw_isobufreq bufreq;
struct fw_pkt *pkt;
struct mpeg_pldt *pld;
uint32_t *ptr;
int fd, k, len, m, pkt_size, startwr, tlen;
char *buf;
startwr = 0;
if (strcmp(filename, "-") == 0)
fd = STDOUT_FILENO;
else {
fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0660);
if (fd == -1)
err(EX_NOINPUT, filename);
}
buf = malloc(RBUFSIZE);
bufreq.rx.nchunk = NCHUNK;
bufreq.rx.npacket = NPACKET_R;
bufreq.rx.psize = PSIZE;
bufreq.tx.nchunk = 0;
bufreq.tx.npacket = 0;
bufreq.tx.psize = 0;
if (ioctl(d, FW_SSTBUF, &bufreq) < 0)
err(1, "ioctl");
isoreq.ch = ich & 0x3f;
isoreq.tag = (ich >> 6) & 3;
if (ioctl(d, FW_SRSTREAM, &isoreq) < 0)
err(1, "ioctl");
k = m = 0;
while (count <= 0 || k <= count) {
len = tlen = read(d, buf, RBUFSIZE);
#if DEBUG
fprintf(stderr, "Read %d bytes.\n", len);
#endif /* DEBUG */
if (len < 0) {
if (errno == EAGAIN) {
fprintf(stderr, "(EAGAIN) - push 'Play'?\n");
if (len <= 0)
continue;
} else
err(1, "read failed");
}
ptr = (uint32_t *) buf;
do {
pkt = (struct fw_pkt *) ptr;
#if DEBUG
fprintf(stderr, "\nReading new packet.\n");
fprintf(stderr, "%08x %08x %08x %08x\n",
htonl(ptr[0]), htonl(ptr[1]),
htonl(ptr[2]), htonl(ptr[3]));
#endif /* DEBUG */
/* there is no CRC in the 1394 header */
ciph = (struct ciphdr *)(ptr + 1); /* skip iso header */
if (ciph->fmt != CIP_FMT_MPEG)
errx(1, "unknown format 0x%x", ciph->fmt);
if (ciph->fn != 3) {
errx(1,
"unsupported MPEG TS stream, fn=%d (only fn=3 is supported)",
ciph->fn);
}
ptr = (uint32_t *) (ciph + 1); /* skip cip header */
if (pkt->mode.stream.len <= sizeof(struct ciphdr)) {
/* no payload */
/* tlen needs to be decremented before end of the loop */
goto next;
}
#if DEBUG
else {
fprintf(stderr,
"Packet net payload length (IEEE1394 header): %d\n",
pkt->mode.stream.len - sizeof(struct ciphdr));
fprintf(stderr, "Data block size (CIP header): %d [q], %d [B]\n",
ciph->len, ciph->len * 4);
fprintf(stderr,
"Data fraction number (CIP header): %d => DBC increments with %d\n",
ciph->fn, (1<<ciph->fn) );
fprintf(stderr, "QCP (CIP header): %d\n", ciph->qpc );
fprintf(stderr, "DBC counter (CIP header): %d\n", ciph->dbc );
fprintf(stderr, "MPEG payload type size: %d\n",
sizeof(struct mpeg_pldt));
}
#endif /* DEBUG */
/* This is a condition that needs to be satisfied to start
writing the data */
if (ciph->dbc % (1<<ciph->fn) == 0)
startwr = 1;
/* Read out all the MPEG TS data blocks from current packet */
for (pld = (struct mpeg_pldt *)ptr;
(intptr_t)pld < (intptr_t)((char *)ptr +
pkt->mode.stream.len - sizeof(struct ciphdr));
pld++) {
if (startwr == 1)
write(fd, pld->payload,
sizeof(pld->payload));
}
next:
/* CRCs are removed from both header and trailer
so that only 4 bytes of 1394 header remains */
pkt_size = pkt->mode.stream.len + 4;
ptr = (uint32_t *)((intptr_t)pkt + pkt_size);
tlen -= pkt_size;
} while (tlen > 0);
#if DEBUG
fprintf(stderr, "\nReading a data from firewire.\n");
#endif /* DEBUG */
}
if (fd != STDOUT_FILENO)
close(fd);
fprintf(stderr, "\n");
}