Add the current version of JiSheng Zhang's firewire_dv media add-on to the
build. This is mostly complete, excepting BBufferConsumer's virtuals are not yet implemented, and needs more testing to ensure that the encoded stream is correctly read from the camera, though based off preliminary tests by Francois, detection/publishing at least seems to work. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27965 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
00acef29d6
commit
b99c736b83
@ -106,6 +106,7 @@ BEOS_ADD_ONS_MEDIA = cortex_audioadapter.media_addon cortex_flanger.media_addon
|
||||
usb_webcam.media_addon
|
||||
video_producer_demo.media_addon
|
||||
video_window_demo.media_addon
|
||||
firewire_dv.media_addon
|
||||
#legacy.media_addon
|
||||
;
|
||||
BEOS_ADD_ONS_MEDIA_PLUGINS = $(GPL_ONLY)ac3_decoder
|
||||
|
@ -15,4 +15,5 @@ SubInclude HAIKU_TOP src add-ons media media-add-ons usb_vision ;
|
||||
SubInclude HAIKU_TOP src add-ons media media-add-ons usb_webcam ;
|
||||
SubInclude HAIKU_TOP src add-ons media media-add-ons video_producer_demo ;
|
||||
SubInclude HAIKU_TOP src add-ons media media-add-ons videowindow ;
|
||||
SubInclude HAIKU_TOP src add-ons media media-add-ons firewire_dv ;
|
||||
|
||||
|
400
src/add-ons/media/media-add-ons/firewire_dv/FireWireCard.cpp
Normal file
400
src/add-ons/media/media-add-ons/firewire_dv/FireWireCard.cpp
Normal file
@ -0,0 +1,400 @@
|
||||
/*
|
||||
* FireWire DV media addon for Haiku
|
||||
*
|
||||
* Copyright (c) 2008, JiSheng Zhang (jszhang3@mail.ustc.edu.cn)
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <OS.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "FireWireCard.h"
|
||||
#include "glue.h"
|
||||
|
||||
#define TAG (1<<6)
|
||||
#define CHANNEL 63
|
||||
|
||||
/* for DV format */
|
||||
#define FIX_FRAME 1
|
||||
|
||||
struct frac {
|
||||
int n,d;
|
||||
};
|
||||
|
||||
struct frac frame_cycle[2] = {
|
||||
{8000*100, 2997}, /* NTSC 8000 cycle / 29.97 Hz */
|
||||
{320, 1}, /* PAL 8000 cycle / 25 Hz */
|
||||
};
|
||||
int npackets[] = {
|
||||
250 /* NTSC */,
|
||||
300 /* PAL */
|
||||
};
|
||||
struct frac pad_rate[2] = {
|
||||
{203, 2997}, /* = (8000 - 29.97 * 250)/(29.97 * 250) */
|
||||
{1, 15}, /* = (8000 - 25 * 300)/(25 * 300) */
|
||||
};
|
||||
char *system_name[] = {"NTSC", "PAL"};
|
||||
int frame_rate[] = {30, 25};
|
||||
|
||||
#define DV_PSIZE 512
|
||||
#define DV_DSIZE 480
|
||||
#define DV_NCHUNK 64
|
||||
|
||||
#define DV_NPACKET_R 256
|
||||
#define DV_NPACKET_T 255
|
||||
#define DV_TNBUF 100 /* XXX too large value causes block noise */
|
||||
#define DV_NEMPTY 10 /* depends on DV_TNBUF */
|
||||
#define DV_RBUFSIZE (DV_PSIZE * DV_NPACKET_R)
|
||||
#define DV_MAXBLOCKS (300)
|
||||
#define DV_CYCLE_FRAC 0xc00
|
||||
|
||||
/* for MPEGTS format */
|
||||
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 MPEG_NCHUNK 8
|
||||
#define MPEG_PSIZE 596
|
||||
#define MPEG_NPACKET_R 4096
|
||||
#define MPEG_RBUFSIZE (MPEG_PSIZE * MPEG_NPACKET_R)
|
||||
|
||||
|
||||
FireWireCard::FireWireCard(const char *path)
|
||||
: fInitStatus(B_OK)
|
||||
, fDev(-1)
|
||||
, fBuf(NULL)
|
||||
, fPad(NULL)
|
||||
{
|
||||
printf("FireWireCard opening %s\n", path);
|
||||
|
||||
fDev = open(path, O_RDWR);
|
||||
if (fDev < 0) {
|
||||
printf("FireWireCard opening %s failed\n", path);
|
||||
fInitStatus = B_ERROR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FireWireCard::~FireWireCard()
|
||||
{
|
||||
if (fDev > 0)
|
||||
close(fDev);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireCard::InitCheck()
|
||||
{
|
||||
return fInitStatus;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
FireWireCard::Read(void **data)
|
||||
{
|
||||
if (fFormat == FMT_MPEGTS)
|
||||
return MpegtsRead(data);
|
||||
else
|
||||
return DvRead(data);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireCard::Extract(void *dest, void **src, ssize_t *sizeUsed)
|
||||
{
|
||||
if (fFormat == FMT_MPEGTS)
|
||||
return MpegtsExtract(dest, src, sizeUsed);
|
||||
else
|
||||
return DvExtract(dest, src, sizeUsed);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FireWireCard::GetBufInfo(size_t *rbufsize, int *rcount)
|
||||
{
|
||||
*rbufsize = fRbufSize;
|
||||
*rcount = fRcount;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireCard::DetectRecvFn()
|
||||
{
|
||||
char *buf, ich = TAG | CHANNEL;
|
||||
struct fw_isochreq isoreq;
|
||||
struct fw_isobufreq bufreq;
|
||||
int len;
|
||||
u_int32_t *ptr;
|
||||
struct ciphdr *ciph;
|
||||
|
||||
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(fDev, FW_SSTBUF, &bufreq) < 0)
|
||||
return errno;
|
||||
|
||||
isoreq.ch = ich & 0x3f;
|
||||
isoreq.tag = (ich >> 6) & 3;
|
||||
|
||||
if (ioctl(fDev, FW_SRSTREAM, &isoreq) < 0)
|
||||
return errno;
|
||||
|
||||
buf = (char *)malloc(1024*16);
|
||||
len = read(fDev, buf, 1024*16);
|
||||
if (len < 0)
|
||||
return errno;
|
||||
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");
|
||||
fFormat = FMT_DV;
|
||||
fBuf = malloc(DV_RBUFSIZE);
|
||||
fRbufSize = DV_PSIZE;
|
||||
fRcount = DV_NPACKET_R;
|
||||
fPad = malloc(DV_DSIZE*DV_MAXBLOCKS);
|
||||
memset(fPad, 0xff, DV_DSIZE*DV_MAXBLOCKS);
|
||||
break;
|
||||
case CIP_FMT_MPEG:
|
||||
fprintf(stderr, "Detected MPEG TS format on input.\n");
|
||||
fFormat = FMT_MPEGTS;
|
||||
fBuf = malloc(MPEG_RBUFSIZE);
|
||||
fRbufSize = MPEG_PSIZE;
|
||||
fRcount = MPEG_NPACKET_R;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported format for receiving: fmt=0x%x", ciph->fmt);
|
||||
}
|
||||
free(buf);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
FireWireCard::DvRead(void **buffer)
|
||||
{
|
||||
struct fw_isochreq isoreq;
|
||||
struct fw_isobufreq bufreq;
|
||||
ssize_t len;
|
||||
char ich = TAG|CHANNEL;
|
||||
|
||||
bufreq.rx.nchunk = DV_NCHUNK;
|
||||
bufreq.rx.npacket = DV_NPACKET_R;
|
||||
bufreq.rx.psize = DV_PSIZE;
|
||||
bufreq.tx.nchunk = 0;
|
||||
bufreq.tx.npacket = 0;
|
||||
bufreq.tx.psize = 0;
|
||||
if (ioctl(fDev, FW_SSTBUF, &bufreq) < 0)
|
||||
return errno;
|
||||
|
||||
isoreq.ch = ich & 0x3f;
|
||||
isoreq.tag = (ich >> 6) & 3;
|
||||
|
||||
if (ioctl(fDev, FW_SRSTREAM, &isoreq) < 0)
|
||||
return errno;
|
||||
|
||||
len = read(fDev, fBuf, DV_RBUFSIZE);
|
||||
if (len < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
fprintf(stderr, "(EAGAIN) - push 'Play'?\n");
|
||||
fflush(stderr);
|
||||
} else
|
||||
fprintf(stderr, "read failed");
|
||||
return errno;
|
||||
}
|
||||
*buffer = fBuf;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireCard::DvExtract(void *dest, void **src, ssize_t *sizeUsed)
|
||||
{
|
||||
struct dvdbc *dv;
|
||||
struct ciphdr *ciph;
|
||||
struct fw_pkt *pkt;
|
||||
u_int32_t *ptr;
|
||||
int nblocks[] = {250 /* NTSC */, 300 /* PAL */};
|
||||
int npad, k, m, system = -1, nb;
|
||||
|
||||
k = m = 0;
|
||||
ptr = (u_int32_t *) (*src);
|
||||
|
||||
pkt = (struct fw_pkt *) ptr;
|
||||
ciph = (struct ciphdr *)(ptr + 1); /* skip iso header */
|
||||
if (ciph->fmt != CIP_FMT_DVCR) {
|
||||
fprintf(stderr, "unknown format 0x%x", ciph->fmt);
|
||||
return B_ERROR;
|
||||
}
|
||||
ptr = (u_int32_t *) (ciph + 1); /* skip cip header */
|
||||
if (pkt->mode.stream.len <= sizeof(struct ciphdr))
|
||||
/* no payload */
|
||||
return B_ERROR;
|
||||
for (dv = (struct dvdbc *)ptr;
|
||||
(char *)dv < (char *)(ptr + ciph->len);
|
||||
dv+=6) {
|
||||
|
||||
if (dv->sct == DV_SCT_HEADER && dv->dseq == 0) {
|
||||
if (system < 0) {
|
||||
system = ciph->fdf.dv.fs;
|
||||
fprintf(stderr, "%s\n", system_name[system]);
|
||||
}
|
||||
|
||||
/* Fix DSF bit */
|
||||
if (system == 1 &&
|
||||
(dv->payload[0] & DV_DSF_12) == 0)
|
||||
dv->payload[0] |= DV_DSF_12;
|
||||
nb = nblocks[system];
|
||||
fprintf(stderr, "%d", k%10);
|
||||
#if FIX_FRAME
|
||||
if (m > 0 && m != nb) {
|
||||
/* padding bad frame */
|
||||
npad = ((nb - m) % nb);
|
||||
if (npad < 0)
|
||||
npad += nb;
|
||||
fprintf(stderr, "(%d blocks padded)",
|
||||
npad);
|
||||
npad *= DV_DSIZE;
|
||||
memcpy(dest, fPad, npad);
|
||||
dest = (char *)dest + npad;
|
||||
}
|
||||
#endif
|
||||
k++;
|
||||
if (k % frame_rate[system] == 0) {
|
||||
/* every second */
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
fflush(stderr);
|
||||
m = 0;
|
||||
}
|
||||
if (k == 0)
|
||||
continue;
|
||||
m++;
|
||||
memcpy(dest, dv, DV_DSIZE);
|
||||
dest = (char *)dest + DV_DSIZE;
|
||||
}
|
||||
ptr = (u_int32_t *)dv;
|
||||
*src = ptr;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
FireWireCard::MpegtsRead(void **buffer)
|
||||
{
|
||||
struct fw_isochreq isoreq;
|
||||
struct fw_isobufreq bufreq;
|
||||
char ich = TAG|CHANNEL;
|
||||
ssize_t len;
|
||||
|
||||
|
||||
bufreq.rx.nchunk = MPEG_NCHUNK;
|
||||
bufreq.rx.npacket = MPEG_NPACKET_R;
|
||||
bufreq.rx.psize = MPEG_PSIZE;
|
||||
bufreq.tx.nchunk = 0;
|
||||
bufreq.tx.npacket = 0;
|
||||
bufreq.tx.psize = 0;
|
||||
if (ioctl(fDev, FW_SSTBUF, &bufreq) < 0)
|
||||
return errno;
|
||||
|
||||
isoreq.ch = ich & 0x3f;
|
||||
isoreq.tag = (ich >> 6) & 3;
|
||||
|
||||
if (ioctl(fDev, FW_SRSTREAM, &isoreq) < 0)
|
||||
return errno;
|
||||
|
||||
len = read(fDev, fBuf, MPEG_RBUFSIZE);
|
||||
if (len < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
fprintf(stderr, "(EAGAIN) - push 'Play'?\n");
|
||||
fflush(stderr);
|
||||
} else
|
||||
fprintf(stderr, "read failed");
|
||||
return errno;
|
||||
}
|
||||
*buffer = fBuf;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireCard::MpegtsExtract(void *dest, void **src, ssize_t *sizeUsed)
|
||||
{
|
||||
uint32_t *ptr;
|
||||
struct fw_pkt *pkt;
|
||||
struct ciphdr *ciph;
|
||||
struct mpeg_pldt *pld;
|
||||
int pkt_size, startwr;
|
||||
|
||||
ptr = (uint32_t *)(*src);
|
||||
startwr = 0;
|
||||
|
||||
pkt = (struct fw_pkt *) ptr;
|
||||
/* there is no CRC in the 1394 header */
|
||||
ciph = (struct ciphdr *)(ptr + 1); /* skip iso header */
|
||||
if (ciph->fmt != CIP_FMT_MPEG) {
|
||||
fprintf(stderr, "unknown format 0x%x", ciph->fmt);
|
||||
return B_ERROR;
|
||||
}
|
||||
if (ciph->fn != 3) {
|
||||
fprintf(stderr, "unsupported MPEG TS stream, fn=%d (only"
|
||||
"fn=3 is supported)", ciph->fn);
|
||||
return B_ERROR;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
memcpy(dest, pld->payload, sizeof(pld->payload));
|
||||
dest = (char *)dest + 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);
|
||||
*src = ptr;
|
||||
return B_OK;
|
||||
}
|
47
src/add-ons/media/media-add-ons/firewire_dv/FireWireCard.h
Normal file
47
src/add-ons/media/media-add-ons/firewire_dv/FireWireCard.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* FireWire DV media addon for Haiku
|
||||
*
|
||||
* Copyright (c) 2008, JiSheng Zhang (jszhang3@mail.ustc.edu.cn)
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __FIREWIRE_CARD_H
|
||||
#define __FIREWIRE_CARD_H
|
||||
|
||||
class FireWireCard
|
||||
{
|
||||
public:
|
||||
enum fmt_type {
|
||||
FMT_MPEGTS = 0,
|
||||
FMT_DV = 1,
|
||||
};
|
||||
FireWireCard(const char *path);
|
||||
~FireWireCard();
|
||||
|
||||
status_t InitCheck();
|
||||
|
||||
status_t DetectRecvFn();
|
||||
ssize_t Read(void **buffer);
|
||||
status_t Extract(void *dest, void **src, ssize_t *sizeUsed);
|
||||
|
||||
void GetBufInfo(size_t *rbufsize, int *rcount);
|
||||
|
||||
private:
|
||||
ssize_t DvRead(void **buffer);
|
||||
status_t DvExtract(void *dest, void **src, ssize_t *sizeUsed);
|
||||
ssize_t MpegtsRead(void **buffer);
|
||||
status_t MpegtsExtract(void *dest, void **src, ssize_t *sizeUsed);
|
||||
|
||||
|
||||
status_t fInitStatus;
|
||||
int fDev;
|
||||
void *fBuf;
|
||||
void *fPad;
|
||||
size_t fRbufSize;
|
||||
int fRcount;
|
||||
fmt_type fFormat;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
183
src/add-ons/media/media-add-ons/firewire_dv/FireWireDVAddOn.cpp
Normal file
183
src/add-ons/media/media-add-ons/firewire_dv/FireWireDVAddOn.cpp
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* FireWire DV media addon for Haiku
|
||||
*
|
||||
* Copyright (c) 2008, JiSheng Zhang (jszhang3@mail.ustc.edu.cn)
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Based on DVB media addon
|
||||
* Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de>
|
||||
*/
|
||||
|
||||
#include "FireWireDVAddOn.h"
|
||||
#include "FireWireCard.h"
|
||||
#include "FireWireDVNode.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <Alert.h>
|
||||
#include <Directory.h>
|
||||
#include <Entry.h>
|
||||
#include <Path.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
struct device_info
|
||||
{
|
||||
FireWireCard * card;
|
||||
char name[16];
|
||||
media_format in_formats[1];
|
||||
media_format out_formats[1];
|
||||
flavor_info flavor;
|
||||
};
|
||||
|
||||
extern "C" BMediaAddOn *
|
||||
make_media_addon(image_id id)
|
||||
{
|
||||
CALLED();
|
||||
return new FireWireDVAddOn(id);
|
||||
}
|
||||
|
||||
FireWireDVAddOn::~FireWireDVAddOn()
|
||||
{
|
||||
CALLED();
|
||||
FreeDeviceList();
|
||||
}
|
||||
|
||||
FireWireDVAddOn::FireWireDVAddOn(image_id id)
|
||||
: BMediaAddOn(id)
|
||||
{
|
||||
CALLED();
|
||||
ScanFolder("/dev/bus/fw");
|
||||
}
|
||||
|
||||
status_t
|
||||
FireWireDVAddOn::InitCheck(const char **out_failure_text)
|
||||
{
|
||||
CALLED();
|
||||
if (!fDeviceList.CountItems()) {
|
||||
*out_failure_text = "No supported device found";
|
||||
return B_ERROR;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
int32
|
||||
FireWireDVAddOn::CountFlavors()
|
||||
{
|
||||
CALLED();
|
||||
return fDeviceList.CountItems();
|
||||
}
|
||||
|
||||
status_t
|
||||
FireWireDVAddOn::GetFlavorAt(int32 n, const flavor_info **out_info)
|
||||
{
|
||||
CALLED();
|
||||
device_info *dev = (device_info *)fDeviceList.ItemAt(n);
|
||||
if (!dev)
|
||||
return B_ERROR;
|
||||
*out_info = &dev->flavor;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
BMediaNode *
|
||||
FireWireDVAddOn::InstantiateNodeFor(const flavor_info *info, BMessage *config, status_t *out_error)
|
||||
{
|
||||
CALLED();
|
||||
device_info *dev = (device_info *)fDeviceList.ItemAt(info->internal_id);
|
||||
if (!dev || dev->flavor.internal_id != info->internal_id) {
|
||||
*out_error = B_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
*out_error = B_OK;
|
||||
|
||||
return new FireWireDVNode(this, dev->name, dev->flavor.internal_id, dev->card);
|
||||
}
|
||||
|
||||
bool
|
||||
FireWireDVAddOn::WantsAutoStart()
|
||||
{
|
||||
CALLED();
|
||||
return false;
|
||||
}
|
||||
|
||||
status_t
|
||||
FireWireDVAddOn::AutoStart(int index, BMediaNode **outNode, int32 *outInternalID, bool *outHasMore)
|
||||
{
|
||||
CALLED();
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
void
|
||||
FireWireDVAddOn::ScanFolder(const char *path)
|
||||
{
|
||||
CALLED();
|
||||
BDirectory dir(path);
|
||||
if (dir.InitCheck() != B_OK)
|
||||
return;
|
||||
|
||||
BEntry ent;
|
||||
|
||||
while (dir.GetNextEntry(&ent) == B_OK) {
|
||||
BPath path(&ent);
|
||||
if (!ent.IsDirectory() && !ent.IsSymLink()) {
|
||||
FireWireCard *card = new FireWireCard(path.Path());
|
||||
if (card->InitCheck() == B_OK)
|
||||
AddDevice(card, path.Path());
|
||||
else
|
||||
delete card;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FireWireDVAddOn::AddDevice(FireWireCard *card, const char *path)
|
||||
{
|
||||
const char *fwnumber;
|
||||
|
||||
// get card name, info and type
|
||||
|
||||
// get interface number
|
||||
const char *p = strrchr(path, '/');
|
||||
fwnumber = p ? p + 1 : "";
|
||||
|
||||
// create device_info
|
||||
device_info *dev = new device_info;
|
||||
fDeviceList.AddItem(dev);
|
||||
|
||||
dev->card = card;
|
||||
|
||||
sprintf(dev->name, "FireWire-%s", fwnumber);
|
||||
|
||||
// setup supported formats (the lazy way)
|
||||
memset(dev->in_formats, 0, sizeof(dev->in_formats));
|
||||
memset(dev->out_formats, 0, sizeof(dev->out_formats));
|
||||
dev->in_formats[1].type = B_MEDIA_ENCODED_VIDEO;
|
||||
dev->out_formats[1].type = B_MEDIA_ENCODED_VIDEO;
|
||||
|
||||
// setup flavor info
|
||||
dev->flavor.name = dev->name;
|
||||
dev->flavor.info = "The FireWireDVNode outputs to fw_raw drivers.";
|
||||
dev->flavor.kinds = B_BUFFER_CONSUMER | B_BUFFER_PRODUCER
|
||||
| B_CONTROLLABLE | B_PHYSICAL_OUTPUT | B_PHYSICAL_INPUT;
|
||||
dev->flavor.flavor_flags = B_FLAVOR_IS_GLOBAL;
|
||||
dev->flavor.internal_id = fDeviceList.CountItems() - 1;
|
||||
dev->flavor.possible_count = 1;
|
||||
dev->flavor.in_format_count = 1;
|
||||
dev->flavor.in_format_flags = 0;
|
||||
dev->flavor.in_formats = dev->in_formats;
|
||||
dev->flavor.out_format_count = 1;
|
||||
dev->flavor.out_format_flags = 0;
|
||||
dev->flavor.out_formats = dev->out_formats;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FireWireDVAddOn::FreeDeviceList()
|
||||
{
|
||||
device_info *dev;
|
||||
while ((dev = (device_info *)fDeviceList.RemoveItem((int32)0))) {
|
||||
delete dev->card;
|
||||
delete dev;
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* FireWire DV media addon for Haiku
|
||||
*
|
||||
* Copyright (c) 2008, JiSheng Zhang (jszhang3@mail.ustc.edu.cn)
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Based on DVB media addon
|
||||
* Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de>
|
||||
*/
|
||||
|
||||
#ifndef _FIREWIRE_DV_ADDON_H_
|
||||
#define _FIREWIRE_DV_ADDON_H_
|
||||
|
||||
#include <MediaAddOn.h>
|
||||
|
||||
class FireWireCard;
|
||||
|
||||
class FireWireDVAddOn : public BMediaAddOn
|
||||
{
|
||||
public:
|
||||
FireWireDVAddOn(image_id id);
|
||||
~FireWireDVAddOn();
|
||||
|
||||
status_t InitCheck(const char **out_failure_text);
|
||||
|
||||
int32 CountFlavors();
|
||||
|
||||
status_t GetFlavorAt(int32 n, const flavor_info **out_info);
|
||||
|
||||
BMediaNode *InstantiateNodeFor(const flavor_info *info, BMessage *config, status_t *out_error);
|
||||
|
||||
bool WantsAutoStart();
|
||||
status_t AutoStart(int index, BMediaNode **outNode, int32 *outInternalID, bool *outHasMore);
|
||||
|
||||
protected:
|
||||
void ScanFolder(const char *path);
|
||||
|
||||
void AddDevice(FireWireCard *card, const char *path);
|
||||
void FreeDeviceList();
|
||||
|
||||
protected:
|
||||
BList fDeviceList;
|
||||
};
|
||||
|
||||
#endif
|
692
src/add-ons/media/media-add-ons/firewire_dv/FireWireDVNode.cpp
Normal file
692
src/add-ons/media/media-add-ons/firewire_dv/FireWireDVNode.cpp
Normal file
@ -0,0 +1,692 @@
|
||||
/*
|
||||
* FireWire DV media addon for Haiku
|
||||
*
|
||||
* Copyright (c) 2008, JiSheng Zhang (jszhang3@mail.ustc.edu.cn)
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Based on DVB media addon
|
||||
* Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de>
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <malloc.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <MediaRoster.h>
|
||||
#include <Buffer.h>
|
||||
#include <BufferGroup.h>
|
||||
#include <ParameterWeb.h>
|
||||
#include <TimeSource.h>
|
||||
#include <String.h>
|
||||
#include <Autolock.h>
|
||||
#include <Debug.h>
|
||||
|
||||
#include <Directory.h>
|
||||
#include <Entry.h>
|
||||
#include <Path.h>
|
||||
|
||||
#include "FireWireDVNode.h"
|
||||
#include "FireWireCard.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define REVISION "unknown"
|
||||
#define VERSION "1.0"
|
||||
#define BUILD __DATE__ " "__TIME__
|
||||
|
||||
// debugging
|
||||
#ifdef TRACE
|
||||
# undef TRACE
|
||||
#endif
|
||||
#define TRACE_FIREWIRE_NODE
|
||||
#ifdef TRACE_FIREWIRE_NODE
|
||||
# define TRACE(x...) printf(x)
|
||||
#else
|
||||
# define TRACE(x...)
|
||||
#endif
|
||||
|
||||
#define RETURN_IF_ERROR(expr) { status_t e = (expr); if (e != B_OK) return e; }
|
||||
|
||||
#define M_REFRESH_PARAMETER_WEB (BTimedEventQueue::B_USER_EVENT + 1)
|
||||
|
||||
FireWireDVNode::FireWireDVNode(
|
||||
BMediaAddOn *addon, const char *name,
|
||||
int32 internal_id, FireWireCard *card)
|
||||
: BMediaNode(name)
|
||||
, BBufferProducer(B_MEDIA_ENCODED_VIDEO)
|
||||
, BControllable()
|
||||
, BMediaEventLooper()
|
||||
, fOutputEnabledEncVideo(false)
|
||||
, fCard(card)
|
||||
, fCaptureThreadsActive(false)
|
||||
, fThreadIdCardReader(-1)
|
||||
, fTerminateThreads(false)
|
||||
, fBufferGroupEncVideo(0)
|
||||
, fCaptureActive(false)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
AddNodeKind(B_PHYSICAL_INPUT);
|
||||
// AddNodeKind(B_PHYSICAL_OUTPUT);
|
||||
|
||||
fInternalID = internal_id;
|
||||
fAddOn = addon;
|
||||
|
||||
fInitStatus = B_OK;
|
||||
|
||||
fDefaultFormatEncVideo.type = B_MEDIA_ENCODED_VIDEO;
|
||||
}
|
||||
|
||||
|
||||
FireWireDVNode::~FireWireDVNode()
|
||||
{
|
||||
CALLED();
|
||||
|
||||
StopCapture();
|
||||
fWeb = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* BMediaNode */
|
||||
|
||||
|
||||
BMediaAddOn *
|
||||
FireWireDVNode::AddOn(int32 *internal_id) const
|
||||
{
|
||||
if (internal_id)
|
||||
*internal_id = fInternalID;
|
||||
return fAddOn;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireDVNode::HandleMessage(int32 message, const void *data, size_t size)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FireWireDVNode::Preroll()
|
||||
{
|
||||
/* This hook may be called before the node is started to give the hardware
|
||||
* a chance to start. */
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FireWireDVNode::SetTimeSource(BTimeSource *time_source)
|
||||
{
|
||||
CALLED();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FireWireDVNode::SetRunMode(run_mode mode)
|
||||
{
|
||||
CALLED();
|
||||
TRACE("FireWireDVNode::SetRunMode(%d)\n", mode);
|
||||
}
|
||||
|
||||
|
||||
/* BMediaEventLooper */
|
||||
|
||||
|
||||
void
|
||||
FireWireDVNode::NodeRegistered()
|
||||
{
|
||||
CALLED();
|
||||
|
||||
SetPriority(B_REAL_TIME_PRIORITY);
|
||||
Run();
|
||||
|
||||
fOutputEncVideo.node = Node();
|
||||
fOutputEncVideo.source.port = ControlPort();
|
||||
fOutputEncVideo.source.id = 0;
|
||||
fOutputEncVideo.destination = media_destination::null;
|
||||
fOutputEncVideo.format = fDefaultFormatEncVideo;
|
||||
strcpy(fOutputEncVideo.name, "encoded video");
|
||||
|
||||
RefreshParameterWeb();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FireWireDVNode::HandleEvent(const media_timed_event *event,
|
||||
bigtime_t lateness, bool realTimeEvent)
|
||||
{
|
||||
|
||||
switch(event->type)
|
||||
{
|
||||
case M_REFRESH_PARAMETER_WEB:
|
||||
RefreshParameterWeb();
|
||||
break;
|
||||
case BTimedEventQueue::B_START:
|
||||
HandleStart(event->event_time);
|
||||
break;
|
||||
case BTimedEventQueue::B_STOP:
|
||||
HandleStop();
|
||||
break;
|
||||
case BTimedEventQueue::B_WARP:
|
||||
HandleTimeWarp(event->bigdata);
|
||||
break;
|
||||
case BTimedEventQueue::B_SEEK:
|
||||
HandleSeek(event->bigdata);
|
||||
break;
|
||||
case BTimedEventQueue::B_HANDLE_BUFFER:
|
||||
case BTimedEventQueue::B_DATA_STATUS:
|
||||
case BTimedEventQueue::B_PARAMETER:
|
||||
default:
|
||||
TRACE("FireWireDVNode::HandleEvent: Unhandled event -- %lx\n", event->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* BBufferProducer */
|
||||
|
||||
|
||||
status_t
|
||||
FireWireDVNode::FormatChangeRequested(const media_source &source,
|
||||
const media_destination &destination, media_format *io_format,
|
||||
int32 *_deprecated_)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
// we don't support any other formats, so we just reject any format changes.
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireDVNode::GetNextOutput(int32 *cookie, media_output *out_output)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
if (*cookie == 0) {
|
||||
*out_output = fOutputEncVideo;
|
||||
*cookie += 1;
|
||||
return B_OK;
|
||||
} else {
|
||||
return B_BAD_INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireDVNode::DisposeOutputCookie(int32 cookie)
|
||||
{
|
||||
CALLED();
|
||||
// do nothing because we don't use the cookie for anything special
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireDVNode::SetBufferGroup(const media_source &source, BBufferGroup *group)
|
||||
{
|
||||
CALLED();
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireDVNode::VideoClippingChanged(const media_source &for_source,
|
||||
int16 num_shorts, int16 *clip_data,
|
||||
const media_video_display_info &display, int32 *_deprecated_)
|
||||
{
|
||||
CALLED();
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireDVNode::GetLatency(bigtime_t *out_latency)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
*out_latency = EventLatency() + SchedulingLatency();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireDVNode::FormatSuggestionRequested(
|
||||
media_type type, int32 quality, media_format *format)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
if (format == NULL) {
|
||||
fprintf(stderr, "\tERROR - NULL format pointer passed in!\n");
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// this is the format we'll be returning (our preferred format)
|
||||
*format = fDefaultFormatEncVideo;
|
||||
|
||||
// a wildcard type is okay; we can specialize it
|
||||
if (type == B_MEDIA_UNKNOWN_TYPE)
|
||||
type = B_MEDIA_ENCODED_VIDEO;
|
||||
|
||||
if (type != B_MEDIA_ENCODED_VIDEO)
|
||||
return B_MEDIA_BAD_FORMAT;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireDVNode::FormatProposal(const media_source &source, media_format *format)
|
||||
{
|
||||
CALLED();
|
||||
/* The connection process:
|
||||
* we are here => BBufferProducer::FormatProposal
|
||||
* BBufferConsumer::AcceptFormat
|
||||
* BBufferProducer::PrepareToConnect
|
||||
* BBufferConsumer::Connected
|
||||
* BBufferProducer::Connect
|
||||
*
|
||||
* What we need to do:
|
||||
* - if the format contains a wildcard AND we have a requirement for that
|
||||
* field, set it to the value we need.
|
||||
* - if a field has a value that is not wildcard and not supported by us,
|
||||
* we don't change it, and return B_MEDIA_BAD_FORMAT
|
||||
* - after we are done, the format may still contain wildcards.
|
||||
*/
|
||||
|
||||
if (source.port != ControlPort()) {
|
||||
fprintf(stderr, "FireWireDVNode::FormatProposal returning "
|
||||
"B_MEDIA_BAD_SOURCE\n");
|
||||
return B_MEDIA_BAD_SOURCE;
|
||||
}
|
||||
|
||||
media_type requestedType = format->type;
|
||||
*format = fDefaultFormatEncVideo;
|
||||
|
||||
if (requestedType != B_MEDIA_UNKNOWN_TYPE
|
||||
&& requestedType != B_MEDIA_ENCODED_VIDEO) {
|
||||
fprintf(stderr, "FireWireDVNode::FormatProposal returning "
|
||||
"B_MEDIA_BAD_FORMAT\n");
|
||||
return B_MEDIA_BAD_FORMAT;
|
||||
}
|
||||
|
||||
// encoded video or wildcard type, either is okay by us
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireDVNode::PrepareToConnect(const media_source &source,
|
||||
const media_destination &destination, media_format *format,
|
||||
media_source *out_source, char *out_name)
|
||||
{
|
||||
/* The connection process:
|
||||
* BBufferProducer::FormatProposal
|
||||
* BBufferConsumer::AcceptFormat
|
||||
* we are here => BBufferProducer::PrepareToConnect
|
||||
* BBufferConsumer::Connected
|
||||
* BBufferProducer::Connect
|
||||
*
|
||||
* At this point, the consumer's AcceptFormat() method has been called,
|
||||
* and that node has potentially changed the proposed format. It may
|
||||
* also have left wildcards in the format. PrepareToConnect()
|
||||
* *must* fully specialize the format before returning!
|
||||
*/
|
||||
|
||||
CALLED();
|
||||
// is the source valid?
|
||||
if (source.port != ControlPort() &&
|
||||
fCard->DetectRecvFn() != B_OK) {
|
||||
fprintf(stderr, "FireWireDVNode::PrepareToConnect returning "
|
||||
"B_MEDIA_BAD_SOURCE\n");
|
||||
return B_MEDIA_BAD_SOURCE;
|
||||
}
|
||||
|
||||
// are we already connected?
|
||||
if (fOutputEncVideo.destination != media_destination::null)
|
||||
return B_MEDIA_ALREADY_CONNECTED;
|
||||
|
||||
// the format may not yet be fully specialized (the consumer might have
|
||||
// passed back some wildcards). Finish specializing it now, and return an
|
||||
// error if we don't support the requested format.
|
||||
if (format->type != B_MEDIA_RAW_AUDIO) {
|
||||
fprintf(stderr, "\tnon-raw-audio format?!\n");
|
||||
return B_MEDIA_BAD_FORMAT;
|
||||
}
|
||||
|
||||
// reserve the connection by setting destination
|
||||
// set the output's format to the new format
|
||||
fOutputEncVideo.destination = destination;
|
||||
fOutputEncVideo.format = *format;
|
||||
|
||||
// set source and suggest a name
|
||||
*out_source = source;
|
||||
strcpy(out_name, "encoded video");
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FireWireDVNode::Connect(status_t error, const media_source &source,
|
||||
const media_destination &destination, const media_format &format,
|
||||
char *io_name)
|
||||
{
|
||||
/* The connection process:
|
||||
* BBufferProducer::FormatProposal
|
||||
* BBufferConsumer::AcceptFormat
|
||||
* BBufferProducer::PrepareToConnect
|
||||
* BBufferConsumer::Connected
|
||||
* we are here => BBufferProducer::Connect
|
||||
*/
|
||||
|
||||
CALLED();
|
||||
|
||||
if (error != B_OK) {
|
||||
TRACE("Error during connecting\n");
|
||||
// if an error occured, unreserve the connection
|
||||
fOutputEncVideo.destination = media_destination::null;
|
||||
fOutputEncVideo.format = fDefaultFormatEncVideo;
|
||||
return;
|
||||
}
|
||||
|
||||
// Since the destination is allowed to be changed by the
|
||||
// consumer, the one we got in PrepareToConnect() is no
|
||||
// longer correct, and must be updated here.
|
||||
fOutputEncVideo.destination = destination;
|
||||
fOutputEncVideo.format = format;
|
||||
|
||||
// if the connection has no name, we set it now
|
||||
if (strlen(io_name) == 0)
|
||||
strcpy(io_name, "encoded video");
|
||||
|
||||
#ifdef DEBUG
|
||||
bigtime_t latency;
|
||||
media_node_id ts;
|
||||
if (B_OK != FindLatencyFor(destination, &latency, &ts))
|
||||
TRACE("FindLatencyFor failed\n");
|
||||
else
|
||||
TRACE("downstream latency %Ld\n", latency);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FireWireDVNode::Disconnect(const media_source &source,
|
||||
const media_destination &destination)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
// unreserve the connection
|
||||
fOutputEncVideo.destination = media_destination::null;
|
||||
fOutputEncVideo.format = fDefaultFormatEncVideo;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FireWireDVNode::LateNoticeReceived(const media_source &source,
|
||||
bigtime_t how_much, bigtime_t performance_time)
|
||||
{
|
||||
TRACE("FireWireDVNode::LateNoticeReceived %Ld late at %Ld\n", how_much, performance_time);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FireWireDVNode::EnableOutput(const media_source &source, bool enabled,
|
||||
int32 *_deprecated_)
|
||||
{
|
||||
CALLED();
|
||||
fOutputEnabledEncVideo = enabled;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FireWireDVNode::AdditionalBufferRequested(const media_source &source,
|
||||
media_buffer_id prev_buffer, bigtime_t prev_time,
|
||||
const media_seek_tag *prev_tag)
|
||||
{
|
||||
CALLED();
|
||||
// we don't support offline mode
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* FireWireDVNode */
|
||||
|
||||
|
||||
void
|
||||
FireWireDVNode::HandleTimeWarp(bigtime_t performance_time)
|
||||
{
|
||||
TRACE("FireWireDVNode::HandleTimeWarp at %Ld\n", performance_time);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FireWireDVNode::HandleSeek(bigtime_t performance_time)
|
||||
{
|
||||
TRACE("FireWireDVNode::HandleSeek at %Ld\n", performance_time);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FireWireDVNode::HandleStart(bigtime_t performance_time)
|
||||
{
|
||||
CALLED();
|
||||
StartCapture();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FireWireDVNode::HandleStop(void)
|
||||
{
|
||||
CALLED();
|
||||
StopCapture();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireDVNode::StartCapture()
|
||||
{
|
||||
CALLED();
|
||||
|
||||
if (fCaptureActive)
|
||||
return B_OK;
|
||||
|
||||
RETURN_IF_ERROR(StopCaptureThreads());
|
||||
|
||||
RETURN_IF_ERROR(StartCaptureThreads());
|
||||
|
||||
fCaptureActive = true;
|
||||
|
||||
RefreshParameterWeb();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireDVNode::StopCapture()
|
||||
{
|
||||
CALLED();
|
||||
if (!fCaptureActive)
|
||||
return B_OK;
|
||||
|
||||
StopCaptureThreads();
|
||||
|
||||
fCaptureActive = false;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireDVNode::StartCaptureThreads()
|
||||
{
|
||||
CALLED();
|
||||
|
||||
if (fCaptureThreadsActive)
|
||||
return B_OK;
|
||||
|
||||
fTerminateThreads = false;
|
||||
|
||||
fThreadIdCardReader = spawn_thread(_card_reader_thread_, "FireWire DV reader", 120, this);
|
||||
resume_thread(fThreadIdCardReader);
|
||||
|
||||
fCaptureThreadsActive = true;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireDVNode::StopCaptureThreads()
|
||||
{
|
||||
CALLED();
|
||||
|
||||
if (!fCaptureThreadsActive)
|
||||
return B_OK;
|
||||
|
||||
fTerminateThreads = true;
|
||||
|
||||
status_t dummy; // NULL as parameter does not work
|
||||
wait_for_thread(fThreadIdCardReader, &dummy);
|
||||
|
||||
fCaptureThreadsActive = false;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
FireWireDVNode::_card_reader_thread_(void *arg)
|
||||
{
|
||||
static_cast<FireWireDVNode *>(arg)->card_reader_thread();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FireWireDVNode::card_reader_thread()
|
||||
{
|
||||
status_t err;
|
||||
size_t rbufsize;
|
||||
int rcount;
|
||||
|
||||
fCard->GetBufInfo(&rbufsize, &rcount);
|
||||
delete fBufferGroupEncVideo;
|
||||
fBufferGroupEncVideo = new BBufferGroup(rbufsize, rcount);
|
||||
while (!fTerminateThreads) {
|
||||
void *data, *end;
|
||||
ssize_t sizeUsed = fCard->Read(&data);
|
||||
if (sizeUsed < 0) {
|
||||
TRACE("FireWireDVNode::%s: %s\n", __FUNCTION__,
|
||||
strerror(sizeUsed));
|
||||
continue;
|
||||
}
|
||||
|
||||
end = (char *)data + sizeUsed;
|
||||
|
||||
while (data < end) {
|
||||
BBuffer *buf = fBufferGroupEncVideo->RequestBuffer(rbufsize, 10000);
|
||||
if (!buf) {
|
||||
TRACE("OutVideo: request buffer timout\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
err = fCard->Extract(buf->Data(), &data, &sizeUsed);
|
||||
if (err) {
|
||||
buf->Recycle();
|
||||
printf("OutVideo Extract error %s\n", strerror(err));
|
||||
continue;
|
||||
}
|
||||
|
||||
media_header* hdr = buf->Header();
|
||||
hdr->type = B_MEDIA_ENCODED_VIDEO;
|
||||
hdr->size_used = sizeUsed;
|
||||
hdr->time_source = TimeSource()->ID(); // set time source id
|
||||
//what should the start_time be?
|
||||
hdr->start_time = TimeSource()->PerformanceTimeFor(system_time());
|
||||
|
||||
lock.Lock();
|
||||
if (B_OK != SendBuffer(buf, fOutputEncVideo.destination)) {
|
||||
TRACE("OutVideo: sending buffer failed\n");
|
||||
buf->Recycle();
|
||||
}
|
||||
lock.Unlock();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FireWireDVNode::RefreshParameterWeb()
|
||||
{
|
||||
TRACE("FireWireDVNode::RefreshParameterWeb enter\n");
|
||||
fWeb = CreateParameterWeb();
|
||||
SetParameterWeb(fWeb);
|
||||
TRACE("FireWireDVNode::RefreshParameterWeb finished\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FireWireDVNode::SetAboutInfo(BParameterGroup *about)
|
||||
{
|
||||
//May need more useful infomation?
|
||||
about->MakeNullParameter(0, B_MEDIA_NO_TYPE, "FireWireDV media_addon info:", B_GENERIC);
|
||||
about->MakeNullParameter(0, B_MEDIA_NO_TYPE, "Version " VERSION, B_GENERIC);
|
||||
about->MakeNullParameter(0, B_MEDIA_NO_TYPE, "Revision " REVISION, B_GENERIC);
|
||||
about->MakeNullParameter(0, B_MEDIA_NO_TYPE, "Build " BUILD, B_GENERIC);
|
||||
|
||||
about->MakeNullParameter(0, B_MEDIA_NO_TYPE, "", B_GENERIC);
|
||||
about->MakeNullParameter(0, B_MEDIA_NO_TYPE, "Driver info:", B_GENERIC);
|
||||
}
|
||||
|
||||
|
||||
BParameterWeb *
|
||||
FireWireDVNode::CreateParameterWeb()
|
||||
{
|
||||
/* Set up the parameter web */
|
||||
BParameterWeb *web = new BParameterWeb();
|
||||
|
||||
BString name;
|
||||
name << Name();
|
||||
|
||||
BParameterGroup *main = web->MakeGroup(name.String());
|
||||
|
||||
if (!fCaptureActive) {
|
||||
BParameterGroup *info = main->MakeGroup("Info");
|
||||
info->MakeNullParameter(0, B_MEDIA_NO_TYPE, info->Name(), B_GENERIC);
|
||||
BParameterGroup *about = main->MakeGroup("About");
|
||||
about->MakeNullParameter(0, B_MEDIA_NO_TYPE, about->Name(), B_GENERIC);
|
||||
SetAboutInfo(about);
|
||||
info->MakeNullParameter(0, B_MEDIA_NO_TYPE, "Node is stopped", B_GENERIC);
|
||||
info->MakeNullParameter(0, B_MEDIA_NO_TYPE, "or tuning failed.", B_GENERIC);
|
||||
return web;
|
||||
}
|
||||
|
||||
BParameterGroup *about = main->MakeGroup("About");
|
||||
about->MakeNullParameter(0, B_MEDIA_NO_TYPE, about->Name(), B_GENERIC);
|
||||
SetAboutInfo(about);
|
||||
|
||||
return web;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FireWireDVNode::GetParameterValue(int32 id, bigtime_t *last_change, void *value, size_t *size)
|
||||
{
|
||||
TRACE("FireWireDVNode::GetParameterValue, id 0x%lx\n", id);
|
||||
//do we need Parameter for firewire dv?
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FireWireDVNode::SetParameterValue(int32 id, bigtime_t when, const void *value, size_t size)
|
||||
{
|
||||
TRACE("FireWireDVNode::SetParameterValue, id 0x%lx, size %ld, value 0x%lx\n", id, size, *(const int32 *)value);
|
||||
//do we need parameter for firewire dv?
|
||||
TRACE("FireWireDVNode::SetParameterValue finished\n");
|
||||
}
|
145
src/add-ons/media/media-add-ons/firewire_dv/FireWireDVNode.h
Normal file
145
src/add-ons/media/media-add-ons/firewire_dv/FireWireDVNode.h
Normal file
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* FireWire DV media addon for Haiku
|
||||
*
|
||||
* Copyright (c) 2008, JiSheng Zhang (jszhang3@mail.ustc.edu.cn)
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Based on DVB media addon
|
||||
* Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de>
|
||||
*/
|
||||
|
||||
#ifndef __FIREWIRE_DV_NODE_H
|
||||
#define __FIREWIRE_DV_NODE_H
|
||||
|
||||
|
||||
#include <OS.h>
|
||||
#include <media/BufferProducer.h>
|
||||
//#include <media/BufferConsumer.h>
|
||||
#include <media/Controllable.h>
|
||||
#include <media/MediaDefs.h>
|
||||
#include <media/MediaEventLooper.h>
|
||||
#include <media/MediaNode.h>
|
||||
#include <support/Locker.h>
|
||||
|
||||
class FireWireCard;
|
||||
class BParameterGroup;
|
||||
|
||||
class FireWireDVNode : public virtual BBufferProducer,
|
||||
public virtual BControllable, public virtual BMediaEventLooper {
|
||||
public:
|
||||
FireWireDVNode(BMediaAddOn *addon,
|
||||
const char *name, int32 internal_id, FireWireCard *card);
|
||||
virtual ~FireWireDVNode();
|
||||
|
||||
virtual status_t InitCheck() const { return fInitStatus; }
|
||||
|
||||
/* BMediaNode */
|
||||
public:
|
||||
virtual BMediaAddOn *AddOn(int32 * internal_id) const;
|
||||
virtual status_t HandleMessage(int32 message, const void *data,
|
||||
size_t size);
|
||||
protected:
|
||||
virtual void Preroll();
|
||||
virtual void SetTimeSource(BTimeSource * time_source);
|
||||
virtual void SetRunMode(run_mode mode);
|
||||
|
||||
/* BMediaEventLooper */
|
||||
protected:
|
||||
virtual void NodeRegistered();
|
||||
|
||||
virtual void HandleEvent(const media_timed_event *event,
|
||||
bigtime_t lateness, bool realTimeEvent = false);
|
||||
|
||||
/* BBufferProducer */
|
||||
protected:
|
||||
virtual status_t FormatSuggestionRequested(media_type type, int32 quality,
|
||||
media_format * format);
|
||||
virtual status_t FormatProposal(const media_source &source,
|
||||
media_format *format);
|
||||
virtual status_t FormatChangeRequested(const media_source &source,
|
||||
const media_destination &destination,
|
||||
media_format *io_format, int32 *_deprecated_);
|
||||
virtual status_t GetNextOutput(int32 * cookie, media_output * out_output);
|
||||
virtual status_t DisposeOutputCookie(int32 cookie);
|
||||
virtual status_t SetBufferGroup(const media_source &for_source,
|
||||
BBufferGroup * group);
|
||||
virtual status_t VideoClippingChanged(const media_source &for_source,
|
||||
int16 num_shorts, int16 *clip_data,
|
||||
const media_video_display_info &display,
|
||||
int32 * _deprecated_);
|
||||
virtual status_t GetLatency(bigtime_t * out_latency);
|
||||
virtual status_t PrepareToConnect(const media_source &what,
|
||||
const media_destination &where,
|
||||
media_format *format,
|
||||
media_source *out_source, char *out_name);
|
||||
virtual void Connect(status_t error, const media_source &source,
|
||||
const media_destination &destination,
|
||||
const media_format & format, char *io_name);
|
||||
virtual void Disconnect(const media_source & what,
|
||||
const media_destination & where);
|
||||
virtual void LateNoticeReceived(const media_source & what,
|
||||
bigtime_t how_much, bigtime_t performance_time);
|
||||
virtual void EnableOutput(const media_source & what, bool enabled,
|
||||
int32 * _deprecated_);
|
||||
virtual void AdditionalBufferRequested(const media_source & source,
|
||||
media_buffer_id prev_buffer, bigtime_t prev_time,
|
||||
const media_seek_tag * prev_tag);
|
||||
|
||||
/* BControllable */
|
||||
protected:
|
||||
virtual status_t GetParameterValue(int32 id, bigtime_t *last_change,
|
||||
void *value, size_t *size);
|
||||
virtual void SetParameterValue(int32 id, bigtime_t when,
|
||||
const void *value, size_t size);
|
||||
|
||||
/* state */
|
||||
private:
|
||||
void HandleStart(bigtime_t performance_time);
|
||||
void HandleStop();
|
||||
void HandleTimeWarp(bigtime_t performance_time);
|
||||
void HandleSeek(bigtime_t performance_time);
|
||||
|
||||
|
||||
BParameterWeb * CreateParameterWeb();
|
||||
void SetAboutInfo(BParameterGroup *about);
|
||||
|
||||
void RefreshParameterWeb();
|
||||
|
||||
status_t StartCapture();
|
||||
status_t StopCapture();
|
||||
status_t StartCaptureThreads();
|
||||
status_t StopCaptureThreads();
|
||||
|
||||
static int32 _card_reader_thread_(void *arg);
|
||||
|
||||
void card_reader_thread();
|
||||
|
||||
status_t fInitStatus;
|
||||
|
||||
int32 fInternalID;
|
||||
BMediaAddOn *fAddOn;
|
||||
|
||||
bool fOutputEnabledEncVideo;
|
||||
|
||||
media_output fOutputEncVideo;
|
||||
|
||||
media_format fDefaultFormatEncVideo;
|
||||
|
||||
FireWireCard * fCard;
|
||||
|
||||
bool fCaptureThreadsActive;
|
||||
|
||||
thread_id fThreadIdCardReader;
|
||||
|
||||
volatile bool fTerminateThreads;
|
||||
|
||||
BBufferGroup * fBufferGroupEncVideo;
|
||||
|
||||
BParameterWeb * fWeb;
|
||||
|
||||
bool fCaptureActive;
|
||||
BLocker lock;
|
||||
|
||||
};
|
||||
|
||||
#endif // __FIREWIRE_DV_NODE_H
|
12
src/add-ons/media/media-add-ons/firewire_dv/Jamfile
Normal file
12
src/add-ons/media/media-add-ons/firewire_dv/Jamfile
Normal file
@ -0,0 +1,12 @@
|
||||
SubDir HAIKU_TOP src add-ons media media-add-ons firewire_dv ;
|
||||
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility bsd ] : true ;
|
||||
UsePrivateHeaders media ;
|
||||
UsePrivateHeaders firewire ;
|
||||
|
||||
Addon firewire_dv.media_addon :
|
||||
FireWireCard.cpp
|
||||
FireWireDVAddOn.cpp
|
||||
FireWireDVNode.cpp
|
||||
: be media
|
||||
;
|
34
src/add-ons/media/media-add-ons/firewire_dv/debug.h
Normal file
34
src/add-ons/media/media-add-ons/firewire_dv/debug.h
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 2
|
||||
#endif
|
||||
|
||||
#if DEBUG >= 1
|
||||
#define UNIMPLEMENTED() printf("UNIMPLEMENTED %s\n",__PRETTY_FUNCTION__)
|
||||
#else
|
||||
#define UNIMPLEMENTED() ((void)0)
|
||||
#endif
|
||||
|
||||
#if DEBUG >= 2
|
||||
#define BROKEN() printf("BROKEN %s\n",__PRETTY_FUNCTION__)
|
||||
#else
|
||||
#define BROKEN() ((void)0)
|
||||
#endif
|
||||
|
||||
#if DEBUG >= 3
|
||||
#define CALLED() printf("CALLED %s\n",__PRETTY_FUNCTION__)
|
||||
#else
|
||||
#define CALLED() ((void)0)
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define UNIMPLEMENTED() ((void)0)
|
||||
#define BROKEN() ((void)0)
|
||||
#define CALLED() ((void)0)
|
||||
|
||||
#endif
|
27
src/add-ons/media/media-add-ons/firewire_dv/glue.h
Normal file
27
src/add-ons/media/media-add-ons/firewire_dv/glue.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* FireWire DV media addon for Haiku
|
||||
*
|
||||
* Copyright (c) 2008, JiSheng Zhang (jszhang3@mail.ustc.edu.cn)
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
*/
|
||||
#ifndef __FIREWIRE_CARD_GLUE_H
|
||||
#define __FIREWIRE_CRAD_GLUE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <endian.h>
|
||||
#include "eui64.h"
|
||||
#include "firewire.h"
|
||||
#include "iec13213.h"
|
||||
#include "fwphyreg.h"
|
||||
#include "iec68113.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user