#include <fcntl.h>
#include <malloc.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <sys/uio.h>
#include <unistd.h>
#include <scheduler.h>
#include <media/Buffer.h>
#include <media/BufferGroup.h>
#include <media/ParameterWeb.h>
#include <media/TimeSource.h>
#include <support/Autolock.h>
#include <support/Debug.h>
#include <app/Message.h>
#include "RadeonAddOn.h"
#include "VideoIn.h"
#define DPRINT(args) { PRINT(("\x1b[0;30;35m")); PRINT(args); PRINT(("\x1b[0;30;47m")); }
#define TOUCH(x) ((void)(x))
#define PRINTF(a,b) \
do { \
if (a < 2) { \
printf("CRadeonProducer::"); \
printf b; \
} \
} while (0)
#include "RadeonProducer.h"
video_in_standard BeToVideoInStandard( int32 be_standard )
{
DPRINT(("BeToVideoInStandard %d \n", be_standard));
switch( be_standard ) {
case 1: return C_VIDEO_IN_NTSC;
case 2: return C_VIDEO_IN_NTSC_JAPAN;
case 3: return C_VIDEO_IN_PAL_BDGHI;
case 4: return C_VIDEO_IN_PAL_M;
case 5: return C_VIDEO_IN_PAL_N;
case 6: return C_VIDEO_IN_SECAM;
case 101: return C_VIDEO_IN_NTSC_443;
case 102: return C_VIDEO_IN_PAL_60;
case 103: return C_VIDEO_IN_PAL_NC;
default: return C_VIDEO_IN_NTSC;
}
}
int32 VideoInStandardToBe( video_in_standard standard )
{
DPRINT(("VideoInStandardToBe %d \n", standard));
switch( standard ) {
case C_VIDEO_IN_NTSC: return 1;
case C_VIDEO_IN_NTSC_JAPAN: return 2;
case C_VIDEO_IN_PAL_BDGHI: return 3;
case C_VIDEO_IN_PAL_M: return 4;
case C_VIDEO_IN_PAL_N: return 5;
case C_VIDEO_IN_SECAM: return 6;
case C_VIDEO_IN_NTSC_443: return 101;
case C_VIDEO_IN_PAL_60: return 102;
case C_VIDEO_IN_PAL_NC: return 103;
default: return 1;
}
}
status_t CRadeonProducer::FindInt32(
BMessage *config, EOptions option, int32 min_value, int32 max_value,
int32 default_value, int32 *value )
{
char name[5];
status_t res;
*value = default_value;
*(int32 *)name = option;
name[4] = 0;
res = config->FindInt32( name, value );
if( res == B_NAME_NOT_FOUND )
return B_OK;
if( res != B_OK )
return res;
*value = MAX( *value, min_value );
*value = MIN( *value, max_value );
return B_OK;
}
CRadeonProducer::CRadeonProducer(
CRadeonAddOn *addon, const char *name, const char *device_name, int32 internal_id,
BMessage *config )
: BMediaNode(name),
BMediaEventLooper(),
BBufferProducer(B_MEDIA_RAW_VIDEO),
BControllable(),
fVideoIn( device_name )
{
DPRINT(("CRadeonProducer::CRadeonProducer()\n"));
fInitStatus = B_NO_INIT;
fInternalID = internal_id;
fAddOn = addon;
fBufferGroup = NULL;
fProcessingLatency = 0LL;
fEnabled = true;
AddNodeKind(B_PHYSICAL_INPUT);
if( fVideoIn.InitCheck() == B_OK )
fInitStatus = B_OK;
fSource = ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) != 0 ? C_VIDEO_IN_TUNER : C_VIDEO_IN_COMPOSITE);
fStandard = C_VIDEO_IN_NTSC;
fMode = C_VIDEO_IN_WEAVE;
fFormat = B_RGB32;
fResolution = 4;
fTuner = 25;
fBrightness = 0;
fContrast = 0;
fSaturation = 0;
fHue = 0;
fSharpness = 0;
if( config != NULL ) {
status_t res;
int32 standard;
if( (res = FindInt32( config, P_SOURCE, 0, C_VIDEO_IN_SOURCE_MAX,
(fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) != 0 ? C_VIDEO_IN_TUNER : C_VIDEO_IN_COMPOSITE,
&fSource )) != B_OK ||
(res = FindInt32( config, P_STANDARD, 0, C_VIDEO_IN_STANDARD_MAX,
C_VIDEO_IN_NTSC, &standard )) != B_OK ||
(res = FindInt32( config, P_MODE, 0, C_VIDEO_IN_CAPTURE_MODE_MAX,
C_VIDEO_IN_FIELD, &fMode )) != B_OK ||
(res = FindInt32( config, P_FORMAT, -2147483647L-1, 2147483647L,
B_RGB16, &fFormat )) != B_OK ||
(res = FindInt32( config, P_RESOLUTION, 0, C_RESOLUTION_MAX,
4, &fResolution )) != B_OK ||
(res = FindInt32( config, P_TUNER, 0, C_CHANNEL_MAX,
25, &fTuner )) != B_OK ||
(res = FindInt32( config, P_BRIGHTNESS, -100, +100,
0, &fBrightness )) != B_OK ||
(res = FindInt32( config, P_CONTRAST, 0, 100,
0, &fContrast )) != B_OK ||
(res = FindInt32( config, P_SATURATION, -100, +100,
0, &fSaturation )) != B_OK ||
(res = FindInt32( config, P_HUE, -90, +90,
0, &fHue )) != B_OK ||
(res = FindInt32( config, P_SHARPNESS, 0, 15,
0, &fSharpness )) != B_OK )
{
DPRINT(("Corrupted settings (%s)\n", strerror( res )));
}
fStandard = VideoInStandardToBe( (video_in_standard)standard );
if( (fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) == 0 )
fSource = C_VIDEO_IN_COMPOSITE;
switch( fFormat ) {
case B_YCbCr422:
case B_GRAY8:
case B_RGB15:
case B_RGB16:
case B_RGB32:
break;
default:
fFormat = B_RGB16;
}
}
fSourceLastChange =
fStandardLastChange =
fModeLastChange =
fFormatLastChange =
fResolutionLastChange =
fTunerLastChange =
fBrightnessLastChange =
fContrastLastChange =
fSaturationLastChange =
fHueLastChange =
fSharpnessLastChange = system_time();
fOutput.destination = media_destination::null;
strcpy(fOutput.name, Name());
fOutput.format.type = B_MEDIA_RAW_VIDEO;
fOutput.format.u.raw_video = media_raw_video_format::wildcard;
}
void CRadeonProducer::setupWeb()
{
BParameterWeb *web = new BParameterWeb();
BParameterGroup *controls = web->MakeGroup("Controls");
BParameterGroup *options = web->MakeGroup("Video");
BParameterGroup *controls1 = controls->MakeGroup("Controls1");
BParameterGroup *controls2 = controls->MakeGroup("Controls2");
BParameterGroup *controls3 = controls->MakeGroup("Controls3");
BParameterGroup *options1 = options->MakeGroup("Options1");
BParameterGroup *options2 = options->MakeGroup("Options2");
if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) != 0) {
BDiscreteParameter *tuner = controls1->MakeDiscreteParameter(
P_TUNER, B_MEDIA_NO_TYPE, "Channel:", B_TUNER_CHANNEL);
for (int channel = 0; channel <= 125; channel++) {
char buffer[32];
sprintf(buffer, "%d", channel);
tuner->AddItem(channel, buffer);
}
}
BDiscreteParameter *source = controls1->MakeDiscreteParameter(
P_SOURCE, B_MEDIA_RAW_VIDEO, "Video Input:", "Video Input:");
if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) != 0)
source->AddItem(C_VIDEO_IN_TUNER, "Tuner");
if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_COMPOSITE) != 0)
source->AddItem(C_VIDEO_IN_COMPOSITE, "Composite");
if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_SVIDEO) != 0)
source->AddItem(C_VIDEO_IN_SVIDEO, "SVideo");
BDiscreteParameter *source2 = controls1->MakeDiscreteParameter(
P_AUDIO_SOURCE, B_MEDIA_RAW_VIDEO, "Audio Input:", "Audio Input:");
if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) != 0)
source2->AddItem(C_VIDEO_IN_TUNER, "Tuner");
controls2->MakeContinuousParameter(P_BRIGHTNESS, B_MEDIA_RAW_VIDEO,"Brightness", "BRIGHTNESS", "", -100, 100, 1);
controls2->MakeContinuousParameter(P_CONTRAST, B_MEDIA_RAW_VIDEO, "Contrast", "CONTRAST", "", 0, 100, 1);
controls2->MakeContinuousParameter(P_SHARPNESS, B_MEDIA_RAW_VIDEO, "Sharpness", B_LEVEL, "dB", 0, 15, 1);
controls3->MakeContinuousParameter(P_SATURATION, B_MEDIA_RAW_VIDEO, "Saturation", "SATURATION", "", -100, 100, 1);
controls3->MakeContinuousParameter(P_HUE, B_MEDIA_RAW_VIDEO, "Hue", B_LEVEL, "°", -90, 90, 1);
BDiscreteParameter *resolution = options1->MakeDiscreteParameter(
P_RESOLUTION, B_MEDIA_RAW_VIDEO, "Default Image Size:", B_RESOLUTION);
resolution->AddItem(6, "768x576");
resolution->AddItem(5, "720x576");
resolution->AddItem(4, "720x480");
resolution->AddItem(0, "640x480");
resolution->AddItem(3, "480x360");
resolution->AddItem(1, "320x240");
resolution->AddItem(2, "160x120");
BDiscreteParameter *format = options1->MakeDiscreteParameter(
P_FORMAT, B_MEDIA_RAW_VIDEO, "Default Colors:", B_COLOR_SPACE);
format->AddItem(B_YCbCr422, "YCbCr422 (fastest)");
format->AddItem(B_GRAY8, "8 Bits/Pixel (gray)");
format->AddItem(B_RGB15, "15 Bits/Pixel");
format->AddItem(B_RGB16, "16 Bits/Pixel");
format->AddItem(B_RGB32, "32 Bits/Pixel");
BDiscreteParameter *standard = options2->MakeDiscreteParameter(
P_STANDARD, B_MEDIA_RAW_VIDEO, "Video Format:", B_VIDEO_FORMAT);
standard->AddItem(1, "NTSC");
standard->AddItem(2, "NTSC Japan");
standard->AddItem(101, "NTSC 443");
standard->AddItem(4, "PAL M");
standard->AddItem(3, "PAL BDGHI");
standard->AddItem(5, "PAL N");
standard->AddItem(102, "PAL 60");
standard->AddItem(103, "PAL NC");
standard->AddItem(6, "SECAM");
BDiscreteParameter *mode = options2->MakeDiscreteParameter(
P_MODE, B_MEDIA_RAW_VIDEO, "Video Interlace:", B_GENERIC);
mode->AddItem(C_VIDEO_IN_FIELD, "Field");
mode->AddItem(C_VIDEO_IN_BOB, "Bob");
mode->AddItem(C_VIDEO_IN_WEAVE, "Weave");
SetParameterWeb(web);
}
CRadeonProducer::~CRadeonProducer()
{
DPRINT(("CRadeonProducer::~CRadeonProducer()\n"));
if (fInitStatus == B_OK) {
HandleStop();
}
delete fBufferGroup;
fBufferGroup = NULL;
BMessage settings;
GetConfiguration( &settings );
fAddOn->UnregisterNode( this, &settings );
Quit();
}
port_id
CRadeonProducer::ControlPort() const
{
return BMediaNode::ControlPort();
}
BMediaAddOn *
CRadeonProducer::AddOn(int32 *internal_id) const
{
if (internal_id)
*internal_id = fInternalID;
return fAddOn;
}
status_t
CRadeonProducer::HandleMessage(int32 message, const void *data, size_t size)
{
switch( message ) {
case C_GET_CONFIGURATION: {
const configuration_msg *request = (const configuration_msg *)data;
BMessage msg;
configuration_msg_reply *reply;
size_t reply_size, config_size;
status_t res;
if( size < sizeof( configuration_msg ))
return B_ERROR;
res = GetConfiguration( &msg );
config_size = msg.FlattenedSize();
reply_size = sizeof( *reply ) + config_size;
reply = (configuration_msg_reply *)malloc( reply_size );
if( reply == NULL )
return B_NO_MEMORY;
reply->res = res;
reply->config_size = config_size;
msg.Flatten( &reply->config, config_size );
write_port_etc( request->reply_port, C_GET_CONFIGURATION_REPLY,
reply, reply_size, B_TIMEOUT, 0 );
free( reply );
return B_OK;
}
default:
return B_ERROR;
}
}
void
CRadeonProducer::Preroll()
{
DPRINT(("CRadeonProducer::Preroll()\n"));
}
void
CRadeonProducer::SetTimeSource(BTimeSource *time_source)
{
DPRINT(("CRadeonProducer::SetTimeSource()\n"));
}
status_t
CRadeonProducer::RequestCompleted(const media_request_info &info)
{
DPRINT(("CRadeonProducer::RequestCompleted()\n"));
return BMediaNode::RequestCompleted(info);
}
void
CRadeonProducer::NodeRegistered()
{
DPRINT(("CRadeonProducer::NodeRegistered()\n"));
if (fInitStatus != B_OK) {
ReportError(B_NODE_IN_DISTRESS);
return;
}
setupWeb();
fOutput.node = Node();
fOutput.source.port = ControlPort();
fOutput.source.id = 0;
SetPriority( suggest_thread_priority( B_VIDEO_RECORDING, 60, 8000, 8000 ));
Run();
}
void
CRadeonProducer::Start(bigtime_t performance_time)
{
DPRINT(("CRadeonProducer::Start()\n"));
BMediaEventLooper::Start(performance_time);
}
void
CRadeonProducer::Stop(bigtime_t performance_time, bool immediate)
{
DPRINT(("CRadeonProducer::Stop()\n"));
BMediaEventLooper::Stop(performance_time, immediate);
}
void
CRadeonProducer::Seek(bigtime_t media_time, bigtime_t performance_time)
{
DPRINT(("CRadeonProducer::Seek()\n"));
BMediaEventLooper::Seek(media_time, performance_time);
}
void
CRadeonProducer::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time)
{
DPRINT(("CRadeonProducer::TimeWarp()\n"));
BMediaEventLooper::TimeWarp(at_real_time, to_performance_time);
}
status_t
CRadeonProducer::AddTimer(bigtime_t at_performance_time, int32 cookie)
{
DPRINT(("CRadeonProducer::AddTimer()\n"));
return BMediaEventLooper::AddTimer(at_performance_time, cookie);
}
void
CRadeonProducer::SetRunMode(run_mode mode)
{
DPRINT(("CRadeonProducer::SetRunMode()\n"));
BMediaEventLooper::SetRunMode(mode);
}
void
CRadeonProducer::HandleEvent(const media_timed_event *event,
bigtime_t lateness, bool realTimeEvent)
{
TOUCH(lateness); TOUCH(realTimeEvent);
switch(event->type)
{
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:
PRINTF(-1, ("HandleEvent: Unhandled event -- %lx\n", event->type));
break;
case BTimedEventQueue::B_HARDWARE:
HandleHardware();
break;
}
}
void
CRadeonProducer::CleanUpEvent(const media_timed_event *event)
{
DPRINT(("CRadeonProducer::CleanUpEvent()\n"));
BMediaEventLooper::CleanUpEvent(event);
}
bigtime_t
CRadeonProducer::OfflineTime()
{
return BMediaEventLooper::OfflineTime();
}
void
CRadeonProducer::ControlLoop()
{
BMediaEventLooper::ControlLoop();
}
status_t
CRadeonProducer::DeleteHook(BMediaNode * node)
{
DPRINT(("CRadeonProducer::DeleteHook()\n"));
return BMediaEventLooper::DeleteHook(node);
}
status_t
CRadeonProducer::verifySetMode( media_format *format )
{
float frame_rate = fVideoIn.getFrameRate(
BeToVideoInStandard( fStandard )) / 1000.0f;
if( format->u.raw_video.interlace == media_raw_video_format::wildcard.interlace ) {
if( format->u.raw_video.field_rate == media_raw_video_format::wildcard.field_rate ) {
format->u.raw_video.interlace = fMode == C_VIDEO_IN_BOB ? 2 : 1;
format->u.raw_video.field_rate = frame_rate * format->u.raw_video.interlace;
} else {
if( format->u.raw_video.field_rate == frame_rate )
format->u.raw_video.interlace = 1;
else if( format->u.raw_video.field_rate == frame_rate * 2 )
format->u.raw_video.interlace = 2;
else {
DPRINT(( "Unsupported field rate for active TV standard (%f)\n",
format->u.raw_video.field_rate ));
return B_MEDIA_BAD_FORMAT;
}
}
} else if( format->u.raw_video.interlace == 1 ) {
if( format->u.raw_video.field_rate == media_raw_video_format::wildcard.field_rate )
format->u.raw_video.field_rate = frame_rate;
else {
if( fabs(format->u.raw_video.field_rate - frame_rate) > 0.001 ) {
DPRINT(( "Wrong field rate for active TV standard (%f) in progressive mode (expected %f)\n",
format->u.raw_video.field_rate - 29.976,
frame_rate - 29.976 ));
return B_MEDIA_BAD_FORMAT;
}
}
} else if( format->u.raw_video.interlace == 2 ) {
if( format->u.raw_video.field_rate == media_raw_video_format::wildcard.field_rate )
format->u.raw_video.field_rate = frame_rate * 2;
else {
if( fabs(format->u.raw_video.field_rate - frame_rate * 2) > 0.001 ) {
DPRINT(( "Wrong field rate for active TV standard (%f) in interlace mode\n",
format->u.raw_video.field_rate ));
return B_MEDIA_BAD_FORMAT;
}
}
} else {
DPRINT(( "Invalid interlace mode (%d)\n", format->u.raw_video.interlace ));
return B_MEDIA_BAD_FORMAT;
}
return B_OK;
}
int32
CRadeonProducer::extractCaptureMode( const media_format *format )
{
if( format->u.raw_video.interlace == 2 )
return C_VIDEO_IN_BOB;
else if( fMode == C_VIDEO_IN_BOB )
return C_VIDEO_IN_WEAVE;
else
return fMode;
}
status_t
CRadeonProducer::verifySetPixelAspect( media_format *format )
{
if( format->u.raw_video.pixel_width_aspect != media_raw_video_format::wildcard.pixel_width_aspect ||
format->u.raw_video.pixel_height_aspect != media_raw_video_format::wildcard.pixel_height_aspect )
{
if( format->u.raw_video.pixel_width_aspect !=
format->u.raw_video.pixel_height_aspect )
{
DPRINT(( "Unsupported pixel aspect (%d:%d)\n",
format->u.raw_video.pixel_width_aspect,
format->u.raw_video.pixel_height_aspect ));
return B_MEDIA_BAD_FORMAT;
}
} else {
format->u.raw_video.pixel_width_aspect = 1;
format->u.raw_video.pixel_height_aspect = 1;
}
return B_OK;
#if 0
if( format->u.raw_video.pixel_width_aspect != media_raw_video_format::wildcard.pixel_width_aspect ||
format->u.raw_video.pixel_height_aspect != media_raw_video_format::wildcard.pixel_height_aspect )
{
double ratio = mode == C_VIDEO_IN_WEAVE ? 1 : 0.5;
if( (float)format->u.raw_video.pixel_width_aspect /
format->u.raw_video.pixel_height_aspect != ratio )
{
DPRINT(( "Unsupported pixel aspect (%d:%d)\n",
format->u.raw_video.pixel_width_aspect,
format->u.raw_video.pixel_height_aspect ));
return B_MEDIA_BAD_FORMAT;
}
} else {
format->u.raw_video.pixel_width_aspect = 1;
format->u.raw_video.pixel_height_aspect =
mode == C_VIDEO_IN_WEAVE ? 1 : 2;
}
return B_OK;
#endif
}
status_t
CRadeonProducer::verifyActiveRange( media_format *format )
{
CRadeonRect active_rect;
fVideoIn.getActiveRange( BeToVideoInStandard( fStandard ), active_rect );
if( format->u.raw_video.first_active != media_raw_video_format::wildcard.first_active ) {
if( (int32)format->u.raw_video.first_active < 0 ) {
DPRINT(( "Unsupported first_active (%d)\n", format->u.raw_video.first_active ));
return B_MEDIA_BAD_FORMAT;
}
}
if( format->u.raw_video.last_active != media_raw_video_format::wildcard.last_active ) {
if( format->u.raw_video.last_active >= (uint32)active_rect.Height() ) {
DPRINT(( "Unsupported last_active (%d)\n", format->u.raw_video.last_active ));
return B_MEDIA_BAD_FORMAT;
}
}
return B_OK;
}
void
CRadeonProducer::setActiveRange( media_format *format )
{
CRadeonRect active_rect;
fVideoIn.getActiveRange( BeToVideoInStandard( fStandard ), active_rect );
if( format->u.raw_video.first_active == media_raw_video_format::wildcard.first_active )
format->u.raw_video.first_active = 0;
if( format->u.raw_video.last_active == media_raw_video_format::wildcard.last_active )
format->u.raw_video.last_active = (uint32)active_rect.Height() - 1;
}
status_t
CRadeonProducer::verifyOrientation( media_format *format )
{
if( format->u.raw_video.orientation != media_raw_video_format::wildcard.orientation ) {
if( format->u.raw_video.orientation != B_VIDEO_TOP_LEFT_RIGHT ) {
DPRINT(( "Unsupported orientation (%d)\n", format->u.raw_video.orientation ));
return B_MEDIA_BAD_FORMAT;
}
}
return B_OK;
}
void
CRadeonProducer::setOrientation( media_format *format )
{
if( format->u.raw_video.orientation == media_raw_video_format::wildcard.orientation )
format->u.raw_video.orientation = B_VIDEO_TOP_LEFT_RIGHT;
}
status_t
CRadeonProducer::verifyPixelFormat( media_format *format )
{
if( format->u.raw_video.display.format !=
media_raw_video_format::wildcard.display.format )
{
switch( format->u.raw_video.display.format ) {
case B_RGB32:
case B_RGB16:
case B_RGB15:
case B_YCbCr422:
case B_GRAY8:
break;
default:
DPRINT(("Unsupported colour space (%x)\n",
format->u.raw_video.display.format ));
return B_MEDIA_BAD_FORMAT;
}
}
return B_OK;
}
void
CRadeonProducer::setPixelFormat( media_format *format )
{
if( format->u.raw_video.display.format ==
media_raw_video_format::wildcard.display.format )
format->u.raw_video.display.format = (color_space)fFormat;
}
status_t
CRadeonProducer::verifySetSize(
media_format *format, int32 mode, bool set_bytes_per_row )
{
CRadeonRect active_rect;
fVideoIn.getActiveRange( BeToVideoInStandard( fStandard ), active_rect );
if( format->u.raw_video.display.line_width !=
media_raw_video_format::wildcard.display.line_width &&
format->u.raw_video.display.line_count !=
media_raw_video_format::wildcard.display.line_count )
{
uint32 max_height = active_rect.Height();
if( mode != C_VIDEO_IN_WEAVE )
max_height /= 2;
if( format->u.raw_video.display.line_width > (uint32)active_rect.Width() ||
format->u.raw_video.display.line_count > max_height )
{
DPRINT(("Requested image size is too high (%dx%d)\n",
format->u.raw_video.display.line_width,
format->u.raw_video.display.line_count));
return B_MEDIA_BAD_FORMAT;
}
if( (format->u.raw_video.display.line_width & 7) != 0 ) {
DPRINT(( "Request image width is not multiple of 8 (%d)\n",
format->u.raw_video.display.line_width ));
return B_MEDIA_BAD_FORMAT;
}
} else {
switch (fResolution) {
case 0:
format->u.raw_video.display.line_width = 640;
format->u.raw_video.display.line_count = 480;
break;
case 3:
format->u.raw_video.display.line_width = 480;
format->u.raw_video.display.line_count = 360;
break;
case 4:
format->u.raw_video.display.line_width = 720;
format->u.raw_video.display.line_count = 480;
break;
case 5:
format->u.raw_video.display.line_width = 720;
format->u.raw_video.display.line_count = 576;
break;
case 6:
format->u.raw_video.display.line_width = 768;
format->u.raw_video.display.line_count = 576;
break;
case 1:
format->u.raw_video.display.line_width = 320;
format->u.raw_video.display.line_count = 240;
break;
case 2:
format->u.raw_video.display.line_width = 160;
format->u.raw_video.display.line_count = 120;
break;
}
if( format->u.raw_video.display.line_width > (uint32)active_rect.Width() )
format->u.raw_video.display.line_width = (uint32)active_rect.Width() & ~7;
if( format->u.raw_video.display.line_count > (uint32)active_rect.Height() )
format->u.raw_video.display.line_count = (uint32)active_rect.Height();
if( mode != C_VIDEO_IN_WEAVE ) {
if( format->u.raw_video.display.line_count > (uint32)active_rect.Height() / 2 )
format->u.raw_video.display.line_count = (uint32)active_rect.Height() / 2;
}
}
if( format->u.raw_video.display.format != media_raw_video_format::wildcard.display.format ) {
uint32 bytes_per_row;
switch( format->u.raw_video.display.format ) {
case B_RGB32:
bytes_per_row =
format->u.raw_video.display.line_width * 4;
break;
case B_RGB15:
case B_RGB16:
case B_YCbCr422:
bytes_per_row =
format->u.raw_video.display.line_width * 2;
break;
default:
bytes_per_row =
format->u.raw_video.display.line_width;
}
if( format->u.raw_video.display.bytes_per_row !=
media_raw_video_format::wildcard.display.bytes_per_row )
{
if( format->u.raw_video.display.bytes_per_row < bytes_per_row ) {
DPRINT(( "Requested bytes per row are too small",
format->u.raw_video.display.bytes_per_row ));
return B_MEDIA_BAD_FORMAT;
}
} else if( set_bytes_per_row )
format->u.raw_video.display.bytes_per_row = bytes_per_row;
}
return B_OK;
}
status_t
CRadeonProducer::verifyFormatOffsets( media_format *format )
{
if( format->u.raw_video.display.pixel_offset !=
media_raw_video_format::wildcard.display.pixel_offset &&
format->u.raw_video.display.pixel_offset != 0 )
{
DPRINT(( "Requested pixel offset is not zero" ));
return B_MEDIA_BAD_FORMAT;
}
if( format->u.raw_video.display.line_offset !=
media_raw_video_format::wildcard.display.line_offset &&
format->u.raw_video.display.line_offset != 0 )
{
DPRINT(( "Requested line offset is not zero" ));
return B_MEDIA_BAD_FORMAT;
}
return B_OK;
}
void
CRadeonProducer::setFormatOffsets( media_format *format )
{
if( format->u.raw_video.display.pixel_offset ==
media_raw_video_format::wildcard.display.pixel_offset )
format->u.raw_video.display.pixel_offset = 0;
if( format->u.raw_video.display.line_offset ==
media_raw_video_format::wildcard.display.line_offset )
format->u.raw_video.display.line_offset = 0;
}
status_t
CRadeonProducer::verifyFormatFlags( media_format *format )
{
if( format->u.raw_video.display.flags !=
media_raw_video_format::wildcard.display.flags &&
format->u.raw_video.display.flags != 0 )
{
DPRINT(( "Requested display flags are not zero" ));
return B_MEDIA_BAD_FORMAT;
}
return B_OK;
}
void
CRadeonProducer::setFormatFlags( media_format *format )
{
if( format->u.raw_video.display.flags ==
media_raw_video_format::wildcard.display.flags )
format->u.raw_video.display.flags = 0;
}
status_t
CRadeonProducer::finalizeFormat( media_format *format )
{
if (format->type != B_MEDIA_RAW_VIDEO)
return B_MEDIA_BAD_FORMAT;
status_t res;
res = verifySetMode( format );
if( res != B_OK )
return res;
int32 mode = extractCaptureMode( format );
res = verifyActiveRange( format );
if( res != B_OK )
return res;
setActiveRange( format );
res = verifyOrientation( format );
if( res != B_OK )
return res;
res = verifySetPixelAspect( format );
if( res != B_OK )
return res;
res = verifyPixelFormat( format );
if( res != B_OK )
return res;
setPixelFormat( format);
res = verifySetSize( format, mode, true );
if( res != B_OK )
return res;
res = verifyFormatOffsets( format );
if( res != B_OK )
return res;
setFormatOffsets( format );
res = verifyFormatFlags( format );
if( res != B_OK )
return res;
setFormatFlags( format );
return res;
}
status_t
CRadeonProducer::FormatSuggestionRequested(
media_type type, int32 quality, media_format *format)
{
DPRINT(("CRadeonProducer::FormatSuggestionRequested()\n"));
if (type != B_MEDIA_RAW_VIDEO)
return B_MEDIA_BAD_FORMAT;
TOUCH(quality);
format->type = B_MEDIA_RAW_VIDEO;
format->u.raw_video = media_raw_video_format::wildcard;
finalizeFormat( format );
return B_OK;
}
status_t
CRadeonProducer::FormatProposal(const media_source &output, media_format *format)
{
char buffer[256];
DPRINT(("CRadeonProducer::FormatProposal()\n"));
if( format == NULL )
return B_BAD_VALUE;
if( output != fOutput.source )
return B_MEDIA_BAD_SOURCE;
string_for_format(*format, buffer, sizeof(buffer));
DPRINT(("CRadeonProducer::FormatProposal() - in=%s\n", buffer));
if( format->type == B_MEDIA_NO_TYPE ) {
format->type = B_MEDIA_RAW_VIDEO;
format->u.raw_video = media_raw_video_format::wildcard;
}
if (format->type != B_MEDIA_RAW_VIDEO)
return B_MEDIA_BAD_FORMAT;
status_t res;
res = verifySetMode( format );
if( res != B_OK )
return res;
int32 mode = extractCaptureMode( format );
res = verifyActiveRange( format );
if( res != B_OK )
return res;
res = verifyOrientation( format );
if( res != B_OK )
return res;
setOrientation( format );
res = verifySetPixelAspect( format );
if( res != B_OK )
return res;
res = verifyPixelFormat( format );
if( res != B_OK )
return res;
setPixelFormat( format );
res = verifySetSize( format, mode, false );
if( res != B_OK )
return res;
res = verifyFormatOffsets( format );
if( res != B_OK )
return res;
res = verifyFormatFlags( format );
if( res != B_OK )
return res;
string_for_format(*format, buffer, sizeof(buffer));
DPRINT(("CRadeonProducer::FormatProposal() - out=%s\n", buffer));
return B_OK;
}
status_t
CRadeonProducer::FormatChangeRequested(const media_source &source,
const media_destination &destination, media_format *io_format,
int32 *_deprecated_)
{
DPRINT(("CRadeonProducer::FormatChangeRequested()\n"));
TOUCH(destination); TOUCH(io_format); TOUCH(_deprecated_);
if (source != fOutput.source)
return B_MEDIA_BAD_SOURCE;
return B_ERROR;
}
status_t
CRadeonProducer::GetNextOutput(int32 *cookie, media_output *out_output)
{
DPRINT(("CRadeonProducer::GetNextOutput()\n"));
if (!out_output)
return B_BAD_VALUE;
if ((*cookie) != 0)
return B_BAD_INDEX;
*out_output = fOutput;
(*cookie)++;
return B_OK;
}
status_t
CRadeonProducer::DisposeOutputCookie(int32 cookie)
{
DPRINT(("CRadeonProducer::DisposeOutputCookie()\n"));
TOUCH(cookie);
return B_OK;
}
status_t
CRadeonProducer::SetBufferGroup(const media_source &for_source,
BBufferGroup *group)
{
DPRINT(("CRadeonProducer::SetBufferGroup()\n"));
if( for_source != fOutput.source )
return B_MEDIA_BAD_SOURCE;
if( group != NULL ) {
delete fBufferGroup;
fBufferGroup = group;
}
return B_OK;
}
status_t
CRadeonProducer::VideoClippingChanged(const media_source &for_source,
int16 num_shorts, int16 *clip_data,
const media_video_display_info &display, int32 *_deprecated_)
{
DPRINT(("CRadeonProducer::VideoClippingChanged()\n"));
TOUCH(for_source); TOUCH(num_shorts); TOUCH(clip_data);
TOUCH(display); TOUCH(_deprecated_);
return B_ERROR;
}
status_t
CRadeonProducer::GetLatency(bigtime_t *out_latency)
{
DPRINT(("CRadeonProducer::GetLatency()\n"));
bigtime_t capture_latency = (bigtime_t)(1000000.0 / fOutput.format.u.raw_video.field_rate);
capture_latency = 0;
bigtime_t buffer_latency = fProcessingLatency;
BBufferProducer::GetLatency( &buffer_latency );
*out_latency = SchedulingLatency() + capture_latency + fProcessingLatency +
buffer_latency;
DPRINT(("latency=%lld\n", *out_latency));
return B_OK;
}
status_t
CRadeonProducer::PrepareToConnect(const media_source &source,
const media_destination &destination, media_format *format,
media_source *out_source, char *out_name)
{
DPRINT(("CRadeonProducer::PrepareToConnect()\n"));
PRINTF(1, ("PrepareToConnect() %ldx%ld\n", \
format->u.raw_video.display.line_width, \
format->u.raw_video.display.line_count));
if (source != fOutput.source) {
DPRINT(("bad source\n"));
return B_MEDIA_BAD_SOURCE;
}
if (fOutput.destination != media_destination::null) {
DPRINT(("already connected\n"));
return B_MEDIA_ALREADY_CONNECTED;
}
char buffer[256];
string_for_format(*format, buffer, sizeof(buffer));
DPRINT(("CRadeonProducer::PrepareToConnect() - in=%s\n", buffer));
status_t res = finalizeFormat( format );
if( res != B_OK )
return res;
*out_source = fOutput.source;
strcpy(out_name, fOutput.name);
string_for_format(*format, buffer, sizeof(buffer));
DPRINT(("CRadeonProducer::PrepareToConnect() - out=%s\n", buffer));
fOutput.destination = destination;
DPRINT(("finished\n"));
return B_OK;
}
void
CRadeonProducer::setDefaultBufferGroup()
{
DPRINT(("CRadeonProducer::setDefaultBufferGroup()\n"));
if( fBufferGroup != NULL ) {
DPRINT(("Buffer already set\n"));
return;
}
fBufferGroup = new BBufferGroup(
fOutput.format.u.raw_video.display.bytes_per_row *
fOutput.format.u.raw_video.display.line_count,
3, B_ANY_ADDRESS, B_FULL_LOCK );
if (fBufferGroup->InitCheck() < B_OK) {
delete fBufferGroup;
fBufferGroup = NULL;
return;
}
}
void
CRadeonProducer::startCapturing()
{
if( RunState() != BMediaEventLooper::B_STARTED ||
fOutput.destination == media_destination::null )
return;
fVideoIn.SetChannel(fTuner, C_VIDEO_IN_NTSC);
fVideoIn.SetBrightness(fBrightness);
fVideoIn.SetContrast(fContrast);
fVideoIn.SetSaturation(fSaturation);
fVideoIn.SetHue(fHue);
fVideoIn.SetSharpness(fSharpness);
fVideoIn.Start(video_in_source(fSource), BeToVideoInStandard( fStandard ),
video_in_capture_mode(fCurMode),
fOutput.format.u.raw_video.display.line_width,
fOutput.format.u.raw_video.display.line_count);
char *tmp_buffer;
tmp_buffer = (char *)malloc(
fOutput.format.u.raw_video.display.bytes_per_row *
fOutput.format.u.raw_video.display.line_count );
int field_sequence;
short field_number;
bigtime_t capture_time;
fVideoIn.Capture(
tmp_buffer != NULL ? fOutput.format.u.raw_video.display.format : B_NO_COLOR_SPACE,
tmp_buffer,
fOutput.format.u.raw_video.display.bytes_per_row * fOutput.format.u.raw_video.display.line_count,
fOutput.format.u.raw_video.display.bytes_per_row,
&field_sequence, &field_number, &capture_time );
for( int i = 0; i < 3; ++i ) {
fVideoIn.Capture(
B_NO_COLOR_SPACE,
NULL,
fOutput.format.u.raw_video.display.bytes_per_row * fOutput.format.u.raw_video.display.line_count,
fOutput.format.u.raw_video.display.bytes_per_row,
&field_sequence, &field_number, &capture_time );
DPRINT(("Captured: %lld, current: %lld\n", capture_time, system_time() ));
}
fVideoIn.Capture(
tmp_buffer != NULL ? fOutput.format.u.raw_video.display.format : B_NO_COLOR_SPACE,
tmp_buffer,
fOutput.format.u.raw_video.display.bytes_per_row * fOutput.format.u.raw_video.display.line_count,
fOutput.format.u.raw_video.display.bytes_per_row,
&field_sequence, &field_number, &capture_time );
DPRINT(("Captured: %lld, current: %lld\n", capture_time, system_time() ));
fProcessingLatency = system_time() - capture_time;
DPRINT(("Processing latency: %dµs\n", fProcessingLatency ));
fFieldSequenceBase = field_sequence;
if( tmp_buffer != NULL )
free(tmp_buffer);
bigtime_t total_latency;
GetLatency( &total_latency );
SetEventLatency( total_latency );
setDefaultBufferGroup();
RealTimeQueue()->FlushEvents( 0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HARDWARE );
media_timed_event event(
capture_time + 1000000 / fOutput.format.u.raw_video.field_rate,
BTimedEventQueue::B_HARDWARE);
RealTimeQueue()->AddEvent(event);
}
void
CRadeonProducer::Connect(status_t error, const media_source &source,
const media_destination &destination, const media_format &format,
char *io_name)
{
if( error != B_OK ) {
DPRINT(( "Connect: Consumer returned error (%s) - releasing source",
strerror( error )));
fOutput.destination = media_destination::null;
return;
}
if( source != fOutput.source ) {
DPRINT(( "Connect: Wrong source specified\n"));
return;
}
fOutput.destination = destination;
fOutput.format = format;
fCurMode = extractCaptureMode( &format );
char buffer[256];
string_for_format(format, buffer, sizeof(buffer));
DPRINT(("CRadeonProducer::Connect() - %s\n", buffer));
strcpy(io_name, fOutput.name);
startCapturing();
DPRINT(("CRadeonProducer::Connect() done\n"));
}
void
CRadeonProducer::Disconnect(const media_source &source,
const media_destination &destination)
{
DPRINT(("Disconnect()\n"));
if( source != fOutput.source || destination != fOutput.destination ) {
DPRINT(("Disconnect: Bad source and/or destination\n"));
return;
}
fOutput.destination = media_destination::null;
delete fBufferGroup;
fBufferGroup = NULL;
fVideoIn.Stop();
RealTimeQueue()->FlushEvents( 0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HARDWARE );
fOutput.format.type = B_MEDIA_RAW_VIDEO;
fOutput.format.u.raw_video = media_raw_video_format::wildcard;
DPRINT(("Disconnect() done\n"));
}
void
CRadeonProducer::LateNoticeReceived(const media_source &source,
bigtime_t how_much, bigtime_t performance_time)
{
DPRINT(("CRadeonProducer::LateNoticeReceived()\n"));
TOUCH(source); TOUCH(how_much); TOUCH(performance_time);
}
void
CRadeonProducer::EnableOutput(const media_source &source, bool enabled,
int32 *_deprecated_)
{
DPRINT(("CRadeonProducer::EnableOutput()\n"));
TOUCH(_deprecated_);
if (source != fOutput.source)
return;
fEnabled = enabled;
}
status_t
CRadeonProducer::SetPlayRate(int32 numer, int32 denom)
{
DPRINT(("CRadeonProducer::SetPlayRate()\n"));
TOUCH(numer); TOUCH(denom);
return B_ERROR;
}
void
CRadeonProducer::AdditionalBufferRequested(const media_source &source,
media_buffer_id prev_buffer, bigtime_t prev_time,
const media_seek_tag *prev_tag)
{
DPRINT(("CRadeonProducer::AdditionalBufferRequested()\n"));
TOUCH(source); TOUCH(prev_buffer); TOUCH(prev_time); TOUCH(prev_tag);
}
void
CRadeonProducer::LatencyChanged(const media_source &source,
const media_destination &destination, bigtime_t new_latency,
uint32 flags)
{
DPRINT(("CRadeonProducer::LatencyChanged()\n"));
BBufferProducer::LatencyChanged( source, destination, new_latency, flags );
}
status_t
CRadeonProducer::GetParameterValue(
int32 id, bigtime_t *last_change, void *value, size_t *size)
{
DPRINT(("CRadeonProducer::GetParameterValue(%d)\n", id));
switch (id) {
case P_SOURCE:
*last_change = fSourceLastChange;
*size = sizeof(fSource);
*((uint32 *) value) = fSource;
break;
case P_STANDARD:
*last_change = fStandardLastChange;
*size = sizeof(fStandard);
*((uint32 *) value) = fStandard;
break;
case P_MODE:
*last_change = fModeLastChange;
*size = sizeof(fMode);
*((uint32 *) value) = fMode;
break;
case P_FORMAT:
*last_change = fFormatLastChange;
*size = sizeof(fFormat);
*((uint32 *) value) = fFormat;
break;
case P_RESOLUTION:
*last_change = fResolutionLastChange;
*size = sizeof(fResolution);
*((uint32 *) value) = fResolution;
break;
case P_TUNER:
*last_change = fTunerLastChange;
*size = sizeof(fTuner);
*((uint32 *) value) = fTuner;
break;
case P_BRIGHTNESS:
*last_change = fBrightnessLastChange;
*size = sizeof(fBrightness);
*((float *) value) = fBrightness;
break;
case P_CONTRAST:
*last_change = fContrastLastChange;
*size = sizeof(fContrast);
*((float *) value) = fContrast;
break;
case P_SATURATION:
*last_change = fSaturationLastChange;
*size = sizeof(fSaturation);
*((float *) value) = fSaturation;
break;
case P_HUE:
*last_change = fHueLastChange;
*size = sizeof(fHue);
*((float *) value) = fHue;
break;
case P_SHARPNESS:
*last_change = fSharpnessLastChange;
*size = sizeof(fSharpness);
*((float *) value) = fSharpness;
break;
default:
DPRINT(("Unknown parameter\n"));
return B_BAD_VALUE;
}
return B_OK;
}
void
CRadeonProducer::instantFormatChange( media_format *new_format )
{
if( fOutput.destination == media_destination::null )
return;
if( finalizeFormat( new_format ) != B_OK ) {
DPRINT(("Current format does not allow to change interlace mode on-the-fly\n"));
return;
}
if( ChangeFormat( fOutput.source, fOutput.destination, new_format ) != B_OK ) {
DPRINT(("Consumer does not allow to change interlace mode instantly\n"));
return;
}
fOutput.format = *new_format;
fCurMode = extractCaptureMode( new_format );
fVideoIn.Stop();
startCapturing();
}
void
CRadeonProducer::SetParameterValue(
int32 id, bigtime_t when, const void *value, size_t size)
{
DPRINT(("CRadeonProducer::SetParameterValue()\n"));
if (!value || size != sizeof(uint32))
return;
switch (id) {
case P_SOURCE:
if (*((const int32 *) value) == fSource)
return;
fSource = *((const uint32 *) value);
fSourceLastChange = when;
break;
case P_STANDARD: {
if (*((const int32 *) value) == fStandard)
return;
fStandard = BeToVideoInStandard( *((const int32 *) value) );
fStandardLastChange = when;
media_format new_format = fOutput.format;
new_format.u.raw_video.field_rate = media_raw_video_format::wildcard.field_rate;
new_format.u.raw_video.interlace = media_raw_video_format::wildcard.interlace;
new_format.u.raw_video.pixel_width_aspect = media_raw_video_format::wildcard.pixel_width_aspect;
new_format.u.raw_video.pixel_height_aspect = media_raw_video_format::wildcard.pixel_height_aspect;
new_format.u.raw_video.first_active = media_raw_video_format::wildcard.first_active;
new_format.u.raw_video.last_active = media_raw_video_format::wildcard.last_active;
instantFormatChange( &new_format );
break; }
case P_MODE: {
if (*((const int32 *) value) == fMode)
return;
fMode = *((const uint32 *) value);
fModeLastChange = when;
media_format new_format = fOutput.format;
new_format.u.raw_video.field_rate = media_raw_video_format::wildcard.field_rate;
new_format.u.raw_video.interlace = media_raw_video_format::wildcard.interlace;
new_format.u.raw_video.pixel_width_aspect = media_raw_video_format::wildcard.pixel_width_aspect;
new_format.u.raw_video.pixel_height_aspect = media_raw_video_format::wildcard.pixel_height_aspect;
instantFormatChange( &new_format );
break; }
case P_FORMAT: {
if (*((const int32 *) value) == fFormat)
return;
fFormat = *((const uint32 *) value);
fFormatLastChange = when;
media_format new_format = fOutput.format;
new_format.u.raw_video.display.format = media_raw_video_format::wildcard.display.format;
new_format.u.raw_video.display.bytes_per_row = media_raw_video_format::wildcard.display.bytes_per_row;
instantFormatChange( &new_format );
break; }
case P_RESOLUTION:
if (*((const int32 *) value) == fResolution)
return;
fResolution = *((const uint32 *) value);
fResolutionLastChange = when;
break;
case P_TUNER:
if (*((const int32 *) value) == fTuner)
return;
fTuner = *((const uint32 *) value);
fTunerLastChange = when;
fVideoIn.SetChannel(fTuner, C_VIDEO_IN_NTSC);
break;
case P_BRIGHTNESS:
if (*((const float *) value) == fBrightness)
return;
fBrightness = (int32)*((const float *) value);
fBrightnessLastChange = when;
fVideoIn.SetBrightness(fBrightness);
break;
case P_CONTRAST:
if (*((const float *) value) == fContrast)
return;
fContrast = (int32)*((const float *) value);
fContrastLastChange = when;
fVideoIn.SetContrast(fContrast);
break;
case P_SATURATION:
if (*((const float *) value) == fSaturation)
return;
fSaturation = (int32)*((const float *) value);
fSaturationLastChange = when;
fVideoIn.SetSaturation(fSaturation);
break;
case P_HUE:
if (*((const float *) value) == fHue)
return;
fHue = (int32)*((const float *) value);
fHueLastChange = when;
fVideoIn.SetHue(fHue);
break;
case P_SHARPNESS:
if (*((const float *) value) == fSharpness)
return;
fSharpness = (int32)*((const float *) value);
fSharpnessLastChange = when;
fVideoIn.SetSharpness(fSharpness);
break;
default:
return;
}
BroadcastNewParameterValue(when, id, const_cast<void *>(value), sizeof(uint32));
}
status_t
CRadeonProducer::StartControlPanel(BMessenger *out_messenger)
{
return BControllable::StartControlPanel(out_messenger);
}
status_t CRadeonProducer::AddInt32(
BMessage *msg, EOptions option, int32 value )
{
char name[5];
*(int32 *)name = option;
name[4] = 0;
return msg->AddInt32( name, value );
}
status_t
CRadeonProducer::GetConfiguration( BMessage *out )
{
status_t res;
if( (res = AddInt32( out, P_SOURCE, fSource )) != B_OK ||
(res = AddInt32( out, P_STANDARD, BeToVideoInStandard( fStandard ))) != B_OK ||
(res = AddInt32( out, P_MODE, fMode )) != B_OK ||
(res = AddInt32( out, P_FORMAT, fFormat )) != B_OK ||
(res = AddInt32( out, P_RESOLUTION, fResolution )) != B_OK ||
(res = AddInt32( out, P_TUNER, fTuner )) != B_OK ||
(res = AddInt32( out, P_BRIGHTNESS, fBrightness )) != B_OK ||
(res = AddInt32( out, P_CONTRAST, fContrast )) != B_OK ||
(res = AddInt32( out, P_SATURATION, fSaturation )) != B_OK ||
(res = AddInt32( out, P_HUE, fHue )) != B_OK ||
(res = AddInt32( out, P_SHARPNESS, fSharpness )) != B_OK )
return res;
return B_OK;
}
void
CRadeonProducer::HandleStart(bigtime_t performance_time)
{
DPRINT(("CRadeonProducer::HandleStart()\n"));
if( RunState() != BMediaEventLooper::B_STOPPED ) {
DPRINT(("already running\n"));
return;
}
SetRunState( BMediaEventLooper::B_STARTED );
startCapturing();
}
void
CRadeonProducer::HandleStop(void)
{
DPRINT(("CRadeonProducer::HandleStop()\n"));
fVideoIn.Stop();
RealTimeQueue()->FlushEvents( 0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HARDWARE );
}
void
CRadeonProducer::HandleTimeWarp(bigtime_t performance_time)
{
DPRINT(("CRadeonProducer::HandleTimeWarp()\n"));
}
void
CRadeonProducer::HandleSeek(bigtime_t performance_time)
{
DPRINT(("CRadeonProducer::HandleSeek()\n"));
}
void
CRadeonProducer::captureField( bigtime_t *capture_time )
{
*capture_time = system_time();
if (!fEnabled)
return;
BBuffer *buffer = fBufferGroup->RequestBuffer(
fOutput.format.u.raw_video.display.bytes_per_row *
fOutput.format.u.raw_video.display.line_count, 0LL);
if (!buffer) {
DPRINT(( "No buffer\n" ));
return;
}
media_header *h = buffer->Header();
h->type = B_MEDIA_RAW_VIDEO;
h->time_source = TimeSource()->ID();
h->size_used = fOutput.format.u.raw_video.display.bytes_per_row *
fOutput.format.u.raw_video.display.line_count;
h->file_pos = 0;
h->orig_size = 0;
h->data_offset = 0;
h->u.raw_video.field_gamma = 1.0;
h->u.raw_video.pulldown_number = 0;
h->u.raw_video.first_active_line = fOutput.format.u.raw_video.first_active;
h->u.raw_video.line_count = fOutput.format.u.raw_video.display.line_count;
int field_sequence;
short field_number;
int dropped=fVideoIn.Capture(
fOutput.format.u.raw_video.display.format,
buffer->Data(),
fOutput.format.u.raw_video.display.bytes_per_row * fOutput.format.u.raw_video.display.line_count,
fOutput.format.u.raw_video.display.bytes_per_row,
&field_sequence,
&field_number,
capture_time);
h->start_time = TimeSource()->PerformanceTimeFor( *capture_time );
h->u.raw_video.field_sequence = field_sequence - fFieldSequenceBase;
h->u.raw_video.field_number = field_number;
if (dropped > 1) {
PRINT(("%d frames dropped\n", dropped-1));
}
if (SendBuffer(buffer, fOutput.destination) < B_OK) {
PRINTF(-1, ("FrameGenerator: Error sending buffer\n"));
buffer->Recycle();
}
}
void
CRadeonProducer::HandleHardware()
{
bigtime_t capture_time;
if( RunState() != BMediaEventLooper::B_STARTED )
return;
captureField( &capture_time );
media_timed_event event(
capture_time + 1000000 / fOutput.format.u.raw_video.field_rate,
BTimedEventQueue::B_HARDWARE);
RealTimeQueue()->AddEvent(event);
}