1 /******************************************************************************
3 / File: RadeonProducer.cpp
5 / Description: ATI Radeon Video Producer media node.
7 / Copyright 2001, Carlos Hasan
9 *******************************************************************************/
18 #include <scheduler.h>
20 #include <media/Buffer.h>
21 #include <media/BufferGroup.h>
22 #include <media/ParameterWeb.h>
23 #include <media/TimeSource.h>
25 #include <support/Autolock.h>
26 #include <support/Debug.h>
28 #include <app/Message.h>
30 #include "RadeonAddOn.h"
33 #define DPRINT(args) { PRINT(("\x1b[0;30;35m")); PRINT(args); PRINT(("\x1b[0;30;47m")); }
35 #define TOUCH(x) ((void)(x))
40 printf("CRadeonProducer::"); \
45 #include "RadeonProducer.h"
47 // convert Be video standard to video-in standard;
48 // Be forgot some standards and define code 7 and 8 to be MPEG1/2, i.e.
49 // didn't leave any space for enhancements, so I chose to use 101 and up;
50 // this way, we get a scattered list of video standards, needing special
51 // functions to convert to scattered Be-code to the compact video-in-code
52 video_in_standard
BeToVideoInStandard( int32 be_standard
)
55 DPRINT(("BeToVideoInStandard %d \n", be_standard
));
56 switch( be_standard
) {
57 case 1: return C_VIDEO_IN_NTSC
;
58 case 2: return C_VIDEO_IN_NTSC_JAPAN
;
59 case 3: return C_VIDEO_IN_PAL_BDGHI
;
60 case 4: return C_VIDEO_IN_PAL_M
;
61 case 5: return C_VIDEO_IN_PAL_N
;
62 case 6: return C_VIDEO_IN_SECAM
;
63 case 101: return C_VIDEO_IN_NTSC_443
;
64 case 102: return C_VIDEO_IN_PAL_60
;
65 case 103: return C_VIDEO_IN_PAL_NC
;
66 default: return C_VIDEO_IN_NTSC
;
70 int32
VideoInStandardToBe( video_in_standard standard
)
72 DPRINT(("VideoInStandardToBe %d \n", standard
));
74 case C_VIDEO_IN_NTSC
: return 1;
75 case C_VIDEO_IN_NTSC_JAPAN
: return 2;
76 case C_VIDEO_IN_PAL_BDGHI
: return 3;
77 case C_VIDEO_IN_PAL_M
: return 4;
78 case C_VIDEO_IN_PAL_N
: return 5;
79 case C_VIDEO_IN_SECAM
: return 6;
80 case C_VIDEO_IN_NTSC_443
: return 101;
81 case C_VIDEO_IN_PAL_60
: return 102;
82 case C_VIDEO_IN_PAL_NC
: return 103;
87 status_t
CRadeonProducer::FindInt32(
88 BMessage
*config
, EOptions option
, int32 min_value
, int32 max_value
,
89 int32 default_value
, int32
*value
)
94 *value
= default_value
;
96 *(int32
*)name
= option
;
99 res
= config
->FindInt32( name
, value
);
100 if( res
== B_NAME_NOT_FOUND
)
106 *value
= MAX( *value
, min_value
);
107 *value
= MIN( *value
, max_value
);
111 CRadeonProducer::CRadeonProducer(
112 CRadeonAddOn
*addon
, const char *name
, const char *device_name
, int32 internal_id
,
116 BBufferProducer(B_MEDIA_RAW_VIDEO
),
118 fVideoIn( device_name
)
120 DPRINT(("CRadeonProducer::CRadeonProducer()\n"));
122 fInitStatus
= B_NO_INIT
;
124 fInternalID
= internal_id
;
128 //fUsedBufferGroup = NULL;
130 fProcessingLatency
= 0LL;
132 //fConnected = false;
135 AddNodeKind(B_PHYSICAL_INPUT
);
137 if( fVideoIn
.InitCheck() == B_OK
)
140 fSource
= ((fVideoIn
.Capabilities() & C_VIDEO_IN_HAS_TUNER
) != 0 ? C_VIDEO_IN_TUNER
: C_VIDEO_IN_COMPOSITE
);
141 fStandard
= C_VIDEO_IN_NTSC
;
142 fMode
= C_VIDEO_IN_WEAVE
;
152 if( config
!= NULL
) {
156 if( (res
= FindInt32( config
, P_SOURCE
, 0, C_VIDEO_IN_SOURCE_MAX
,
157 (fVideoIn
.Capabilities() & C_VIDEO_IN_HAS_TUNER
) != 0 ? C_VIDEO_IN_TUNER
: C_VIDEO_IN_COMPOSITE
,
158 &fSource
)) != B_OK
||
159 (res
= FindInt32( config
, P_STANDARD
, 0, C_VIDEO_IN_STANDARD_MAX
,
160 C_VIDEO_IN_NTSC
, &standard
)) != B_OK
||
161 (res
= FindInt32( config
, P_MODE
, 0, C_VIDEO_IN_CAPTURE_MODE_MAX
,
162 C_VIDEO_IN_FIELD
, &fMode
)) != B_OK
||
163 (res
= FindInt32( config
, P_FORMAT
, -2147483647L-1, 2147483647L,
164 B_RGB16
, &fFormat
)) != B_OK
||
165 (res
= FindInt32( config
, P_RESOLUTION
, 0, C_RESOLUTION_MAX
,
166 4, &fResolution
)) != B_OK
||
167 (res
= FindInt32( config
, P_TUNER
, 0, C_CHANNEL_MAX
,
168 25, &fTuner
)) != B_OK
||
169 (res
= FindInt32( config
, P_BRIGHTNESS
, -100, +100,
170 0, &fBrightness
)) != B_OK
||
171 (res
= FindInt32( config
, P_CONTRAST
, 0, 100,
172 0, &fContrast
)) != B_OK
||
173 (res
= FindInt32( config
, P_SATURATION
, -100, +100,
174 0, &fSaturation
)) != B_OK
||
175 (res
= FindInt32( config
, P_HUE
, -90, +90,
176 0, &fHue
)) != B_OK
||
177 (res
= FindInt32( config
, P_SHARPNESS
, 0, 15,
178 0, &fSharpness
)) != B_OK
)
180 DPRINT(("Corrupted settings (%s)\n", strerror( res
)));
183 // standard is stored as internal code (which has no "holes" in its numbering);
184 // time to convert it
185 // if this value comes from our setup web is it not already linear?
186 fStandard
= VideoInStandardToBe( (video_in_standard
)standard
);
188 // if there is no tuner, force composite input
189 if( (fVideoIn
.Capabilities() & C_VIDEO_IN_HAS_TUNER
) == 0 )
190 fSource
= C_VIDEO_IN_COMPOSITE
;
192 // format ids are scattered, so we must verify them manually
206 fStandardLastChange
=
209 fResolutionLastChange
=
211 fBrightnessLastChange
=
212 fContrastLastChange
=
213 fSaturationLastChange
=
215 fSharpnessLastChange
= system_time();
217 fOutput
.destination
= media_destination::null
;
218 strcpy(fOutput
.name
, Name());
220 // we provide interlaced raw video in any format
221 fOutput
.format
.type
= B_MEDIA_RAW_VIDEO
;
222 fOutput
.format
.u
.raw_video
= media_raw_video_format::wildcard
;
226 void CRadeonProducer::setupWeb()
229 /* Set up the parameter web */
231 // in "kind" value of parameters is "stampTV-compatible", i.e.
232 // if not defined, we use the name used in stampTV
233 BParameterWeb
*web
= new BParameterWeb();
234 BParameterGroup
*controls
= web
->MakeGroup("Controls");
235 BParameterGroup
*options
= web
->MakeGroup("Video");
236 /*BParameterGroup *audio = web->MakeGroup("Audio");*/
238 BParameterGroup
*controls1
= controls
->MakeGroup("Controls1");
239 BParameterGroup
*controls2
= controls
->MakeGroup("Controls2");
240 BParameterGroup
*controls3
= controls
->MakeGroup("Controls3");
242 BParameterGroup
*options1
= options
->MakeGroup("Options1");
243 BParameterGroup
*options2
= options
->MakeGroup("Options2");
245 /*BParameterGroup *audio1 = audio->MakeGroup("Audio1");
246 BParameterGroup *audio2 = audio->MakeGroup("Audio2");*/
250 if ((fVideoIn
.Capabilities() & C_VIDEO_IN_HAS_TUNER
) != 0) {
252 BDiscreteParameter
*tuner
= controls1
->MakeDiscreteParameter(
253 P_TUNER
, B_MEDIA_NO_TYPE
, "Channel:", B_TUNER_CHANNEL
);
255 for (int channel
= 0; channel
<= 125; channel
++) {
257 sprintf(buffer
, "%d", channel
);
258 tuner
->AddItem(channel
, buffer
);
263 BDiscreteParameter
*source
= controls1
->MakeDiscreteParameter(
264 P_SOURCE
, B_MEDIA_RAW_VIDEO
, "Video Input:", "Video Input:");
266 if ((fVideoIn
.Capabilities() & C_VIDEO_IN_HAS_TUNER
) != 0)
267 source
->AddItem(C_VIDEO_IN_TUNER
, "Tuner");
268 if ((fVideoIn
.Capabilities() & C_VIDEO_IN_HAS_COMPOSITE
) != 0)
269 source
->AddItem(C_VIDEO_IN_COMPOSITE
, "Composite");
270 if ((fVideoIn
.Capabilities() & C_VIDEO_IN_HAS_SVIDEO
) != 0)
271 source
->AddItem(C_VIDEO_IN_SVIDEO
, "SVideo");
274 BDiscreteParameter
*source2
= controls1
->MakeDiscreteParameter(
275 P_AUDIO_SOURCE
, B_MEDIA_RAW_VIDEO
, "Audio Input:", "Audio Input:");
276 if ((fVideoIn
.Capabilities() & C_VIDEO_IN_HAS_TUNER
) != 0)
277 source2
->AddItem(C_VIDEO_IN_TUNER
, "Tuner");
278 /* if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_COMPOSITE) != 0)
279 source2->AddItem(C_VIDEO_IN_COMPOSITE, "Composite");
280 if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_SVIDEO) != 0)
281 source2->AddItem(C_VIDEO_IN_SVIDEO, "SVideo");
284 // Controls.Brightness/Contrast/Saturation/Hue
285 controls2
->MakeContinuousParameter(P_BRIGHTNESS
, B_MEDIA_RAW_VIDEO
,"Brightness", "BRIGHTNESS", "", -100, 100, 1);
286 controls2
->MakeContinuousParameter(P_CONTRAST
, B_MEDIA_RAW_VIDEO
, "Contrast", "CONTRAST", "", 0, 100, 1);
287 controls2
->MakeContinuousParameter(P_SHARPNESS
, B_MEDIA_RAW_VIDEO
, "Sharpness", B_LEVEL
, "dB", 0, 15, 1);
289 controls3
->MakeContinuousParameter(P_SATURATION
, B_MEDIA_RAW_VIDEO
, "Saturation", "SATURATION", "", -100, 100, 1);
290 controls3
->MakeContinuousParameter(P_HUE
, B_MEDIA_RAW_VIDEO
, "Hue", B_LEVEL
, "°", -90, 90, 1);
293 // Options.Resolution
294 BDiscreteParameter
*resolution
= options1
->MakeDiscreteParameter(
295 P_RESOLUTION
, B_MEDIA_RAW_VIDEO
, "Default Image Size:", B_RESOLUTION
);
297 resolution
->AddItem(6, "768x576");
298 resolution
->AddItem(5, "720x576");
299 resolution
->AddItem(4, "720x480");
300 resolution
->AddItem(0, "640x480");
301 resolution
->AddItem(3, "480x360");
302 resolution
->AddItem(1, "320x240");
303 resolution
->AddItem(2, "160x120");
306 BDiscreteParameter
*format
= options1
->MakeDiscreteParameter(
307 P_FORMAT
, B_MEDIA_RAW_VIDEO
, "Default Colors:", B_COLOR_SPACE
);
309 format
->AddItem(B_YCbCr422
, "YCbCr422 (fastest)");
310 format
->AddItem(B_GRAY8
, "8 Bits/Pixel (gray)");
311 format
->AddItem(B_RGB15
, "15 Bits/Pixel");
312 format
->AddItem(B_RGB16
, "16 Bits/Pixel");
313 format
->AddItem(B_RGB32
, "32 Bits/Pixel");
316 BDiscreteParameter
*standard
= options2
->MakeDiscreteParameter(
317 P_STANDARD
, B_MEDIA_RAW_VIDEO
, "Video Format:", B_VIDEO_FORMAT
);
319 standard
->AddItem(1, "NTSC");
320 standard
->AddItem(2, "NTSC Japan");
321 standard
->AddItem(101, "NTSC 443");
322 standard
->AddItem(4, "PAL M");
323 standard
->AddItem(3, "PAL BDGHI");
324 standard
->AddItem(5, "PAL N");
325 standard
->AddItem(102, "PAL 60");
326 standard
->AddItem(103, "PAL NC");
327 standard
->AddItem(6, "SECAM");
330 BDiscreteParameter
*mode
= options2
->MakeDiscreteParameter(
331 P_MODE
, B_MEDIA_RAW_VIDEO
, "Video Interlace:", B_GENERIC
);
333 mode
->AddItem(C_VIDEO_IN_FIELD
, "Field");
334 mode
->AddItem(C_VIDEO_IN_BOB
, "Bob");
335 mode
->AddItem(C_VIDEO_IN_WEAVE
, "Weave");
340 BDiscreteParameter *standard2 = audio1->MakeDiscreteParameter(
341 P_AUDIO_FORMAT, B_MEDIA_RAW_VIDEO, "Audio Format:", B_VIDEO_FORMAT);
342 standard2->AddItem(0, "Stereo");
343 standard2->AddItem(1, "Mono");
344 standard2->AddItem(2, "NICAM");
346 BDiscreteParameter *audioSource = audio1->MakeDiscreteParameter(
347 P_AUDIO_FORMAT, B_MEDIA_RAW_VIDEO, "Audio Source:", B_VIDEO_FORMAT);
348 audioSource->AddItem(0, "FM");
349 audioSource->AddItem(1, "Stereo");
350 audioSource->AddItem(2, "SCART");
351 audioSource->AddItem(3, "Language A");
352 audioSource->AddItem(4, "Language B");
354 BDiscreteParameter *matrix= audio2->MakeDiscreteParameter(
355 P_AUDIO_FORMAT, B_MEDIA_RAW_VIDEO, "Audio Matrix:", B_VIDEO_FORMAT);
356 matrix->AddItem(0, "Sound A");
357 matrix->AddItem(1, "Sound B");
358 matrix->AddItem(2, "Stereo");
359 matrix->AddItem(3, "Mono");*/
361 /* After this call, the BControllable owns the BParameterWeb object and
362 * will delete it for you */
363 SetParameterWeb(web
);
367 CRadeonProducer::~CRadeonProducer()
369 DPRINT(("CRadeonProducer::~CRadeonProducer()\n"));
371 if (fInitStatus
== B_OK
) {
372 /* Clean up after ourselves, in case the application didn't make us
375 Disconnect(fOutput.source, fOutput.destination);*/
385 GetConfiguration( &settings
);
387 fAddOn
->UnregisterNode( this, &settings
);
395 CRadeonProducer::ControlPort() const
397 return BMediaNode::ControlPort();
401 CRadeonProducer::AddOn(int32
*internal_id
) const
404 *internal_id
= fInternalID
;
409 CRadeonProducer::HandleMessage(int32 message
, const void *data
, size_t size
)
411 //DPRINT(("CRadeonProducer::HandleMessage()\n"));
414 case C_GET_CONFIGURATION
: {
415 const configuration_msg
*request
= (const configuration_msg
*)data
;
417 configuration_msg_reply
*reply
;
418 size_t reply_size
, config_size
;
421 if( size
< sizeof( configuration_msg
))
424 res
= GetConfiguration( &msg
);
426 config_size
= msg
.FlattenedSize();
427 reply_size
= sizeof( *reply
) + config_size
;
428 reply
= (configuration_msg_reply
*)malloc( reply_size
);
433 reply
->config_size
= config_size
;
434 msg
.Flatten( &reply
->config
, config_size
);
436 write_port_etc( request
->reply_port
, C_GET_CONFIGURATION_REPLY
,
437 reply
, reply_size
, B_TIMEOUT
, 0 );
444 // return BControllable::HandleMessage(message, data, size);
449 CRadeonProducer::Preroll()
451 /* This hook may be called before the node is started to give the hardware
452 * a chance to start. */
453 DPRINT(("CRadeonProducer::Preroll()\n"));
457 CRadeonProducer::SetTimeSource(BTimeSource
*time_source
)
459 DPRINT(("CRadeonProducer::SetTimeSource()\n"));
461 /* Tell frame generation thread to recalculate delay value */
462 //release_sem(fFrameSync);
466 CRadeonProducer::RequestCompleted(const media_request_info
&info
)
468 DPRINT(("CRadeonProducer::RequestCompleted()\n"));
470 return BMediaNode::RequestCompleted(info
);
473 /* BMediaEventLooper */
476 CRadeonProducer::NodeRegistered()
478 DPRINT(("CRadeonProducer::NodeRegistered()\n"));
480 if (fInitStatus
!= B_OK
) {
481 ReportError(B_NODE_IN_DISTRESS
);
488 fOutput
.node
= Node();
489 fOutput
.source
.port
= ControlPort();
490 fOutput
.source
.id
= 0;
492 /* Tailor these for the output of your device */
494 fOutput.format.type = B_MEDIA_RAW_VIDEO;
495 fOutput.format.u.raw_video = media_raw_video_format::wildcard;
496 // fOutput.format.u.raw_video.interlace = 1;
497 fOutput.format.u.raw_video.display.format = B_RGB32;
500 // up to 60 frames (NTSC); jitter less then half a frame; processing time
501 // depends on whether colour space conversion is required, let's say half
502 // a frame in worst case
503 SetPriority( suggest_thread_priority( B_VIDEO_RECORDING
, 60, 8000, 8000 ));
505 /* Start the BMediaEventLooper control loop running */
510 CRadeonProducer::Start(bigtime_t performance_time
)
512 DPRINT(("CRadeonProducer::Start()\n"));
514 BMediaEventLooper::Start(performance_time
);
518 CRadeonProducer::Stop(bigtime_t performance_time
, bool immediate
)
520 DPRINT(("CRadeonProducer::Stop()\n"));
522 BMediaEventLooper::Stop(performance_time
, immediate
);
526 CRadeonProducer::Seek(bigtime_t media_time
, bigtime_t performance_time
)
528 DPRINT(("CRadeonProducer::Seek()\n"));
530 BMediaEventLooper::Seek(media_time
, performance_time
);
534 CRadeonProducer::TimeWarp(bigtime_t at_real_time
, bigtime_t to_performance_time
)
536 DPRINT(("CRadeonProducer::TimeWarp()\n"));
538 BMediaEventLooper::TimeWarp(at_real_time
, to_performance_time
);
542 CRadeonProducer::AddTimer(bigtime_t at_performance_time
, int32 cookie
)
544 DPRINT(("CRadeonProducer::AddTimer()\n"));
546 return BMediaEventLooper::AddTimer(at_performance_time
, cookie
);
550 CRadeonProducer::SetRunMode(run_mode mode
)
552 DPRINT(("CRadeonProducer::SetRunMode()\n"));
554 BMediaEventLooper::SetRunMode(mode
);
558 CRadeonProducer::HandleEvent(const media_timed_event
*event
,
559 bigtime_t lateness
, bool realTimeEvent
)
561 //DPRINT(("CRadeonProducer::HandleEvent()\n"));
563 TOUCH(lateness
); TOUCH(realTimeEvent
);
567 case BTimedEventQueue::B_START
:
568 HandleStart(event
->event_time
);
570 case BTimedEventQueue::B_STOP
:
573 case BTimedEventQueue::B_WARP
:
574 HandleTimeWarp(event
->bigdata
);
576 case BTimedEventQueue::B_SEEK
:
577 HandleSeek(event
->bigdata
);
579 case BTimedEventQueue::B_HANDLE_BUFFER
:
580 case BTimedEventQueue::B_DATA_STATUS
:
581 case BTimedEventQueue::B_PARAMETER
:
583 PRINTF(-1, ("HandleEvent: Unhandled event -- %lx\n", event
->type
));
585 case BTimedEventQueue::B_HARDWARE
:
590 //DPRINT(("CRadeonProducer::HandleEvent() done\n"));
594 CRadeonProducer::CleanUpEvent(const media_timed_event
*event
)
596 DPRINT(("CRadeonProducer::CleanUpEvent()\n"));
598 BMediaEventLooper::CleanUpEvent(event
);
602 CRadeonProducer::OfflineTime()
604 return BMediaEventLooper::OfflineTime();
608 CRadeonProducer::ControlLoop()
610 BMediaEventLooper::ControlLoop();
614 CRadeonProducer::DeleteHook(BMediaNode
* node
)
616 DPRINT(("CRadeonProducer::DeleteHook()\n"));
618 return BMediaEventLooper::DeleteHook(node
);
623 /* BBufferProducer */
625 // choose capture mode according to format and update format according to that
627 CRadeonProducer::verifySetMode( media_format
*format
)
629 float frame_rate
= fVideoIn
.getFrameRate(
630 BeToVideoInStandard( fStandard
)) / 1000.0f
;
632 if( format
->u
.raw_video
.interlace
== media_raw_video_format::wildcard
.interlace
) {
633 if( format
->u
.raw_video
.field_rate
== media_raw_video_format::wildcard
.field_rate
) {
634 format
->u
.raw_video
.interlace
= fMode
== C_VIDEO_IN_BOB
? 2 : 1;
635 format
->u
.raw_video
.field_rate
= frame_rate
* format
->u
.raw_video
.interlace
;
637 if( format
->u
.raw_video
.field_rate
== frame_rate
)
638 format
->u
.raw_video
.interlace
= 1;
639 else if( format
->u
.raw_video
.field_rate
== frame_rate
* 2 )
640 format
->u
.raw_video
.interlace
= 2;
642 DPRINT(( "Unsupported field rate for active TV standard (%f)\n",
643 format
->u
.raw_video
.field_rate
));
644 return B_MEDIA_BAD_FORMAT
;
648 } else if( format
->u
.raw_video
.interlace
== 1 ) {
649 if( format
->u
.raw_video
.field_rate
== media_raw_video_format::wildcard
.field_rate
)
650 format
->u
.raw_video
.field_rate
= frame_rate
;
652 // don't compare directly - there are rounding errors
653 if( fabs(format
->u
.raw_video
.field_rate
- frame_rate
) > 0.001 ) {
654 DPRINT(( "Wrong field rate for active TV standard (%f) in progressive mode (expected %f)\n",
655 format
->u
.raw_video
.field_rate
- 29.976,
656 frame_rate
- 29.976 ));
657 return B_MEDIA_BAD_FORMAT
;
661 } else if( format
->u
.raw_video
.interlace
== 2 ) {
662 if( format
->u
.raw_video
.field_rate
== media_raw_video_format::wildcard
.field_rate
)
663 format
->u
.raw_video
.field_rate
= frame_rate
* 2;
665 if( fabs(format
->u
.raw_video
.field_rate
- frame_rate
* 2) > 0.001 ) {
666 DPRINT(( "Wrong field rate for active TV standard (%f) in interlace mode\n",
667 format
->u
.raw_video
.field_rate
));
668 return B_MEDIA_BAD_FORMAT
;
673 DPRINT(( "Invalid interlace mode (%d)\n", format
->u
.raw_video
.interlace
));
674 return B_MEDIA_BAD_FORMAT
;
681 Map BeOS capture mode to internal capture mode.
684 CRadeonProducer::extractCaptureMode( const media_format
*format
)
686 // if application requests interlace, it always gets BOB;
687 // if is requests non-interlace, it may get WEAVE or FIELD -
688 // if the user selected one of them, we are fine; else,
689 // we always choose WEAVE (could choose FIELD as well, make
690 // it dependant on resolution, but the more magic the more problems)
691 if( format
->u
.raw_video
.interlace
== 2 )
692 return C_VIDEO_IN_BOB
;
693 else if( fMode
== C_VIDEO_IN_BOB
)
694 return C_VIDEO_IN_WEAVE
;
699 // check pixel aspect of format and set it if it's wildcarded
701 CRadeonProducer::verifySetPixelAspect( media_format
*format
)
703 // for simplicity, we always assume 1:1 aspect
704 if( format
->u
.raw_video
.pixel_width_aspect
!= media_raw_video_format::wildcard
.pixel_width_aspect
||
705 format
->u
.raw_video
.pixel_height_aspect
!= media_raw_video_format::wildcard
.pixel_height_aspect
)
707 if( format
->u
.raw_video
.pixel_width_aspect
!=
708 format
->u
.raw_video
.pixel_height_aspect
)
710 DPRINT(( "Unsupported pixel aspect (%d:%d)\n",
711 format
->u
.raw_video
.pixel_width_aspect
,
712 format
->u
.raw_video
.pixel_height_aspect
));
713 return B_MEDIA_BAD_FORMAT
;
716 format
->u
.raw_video
.pixel_width_aspect
= 1;
717 format
->u
.raw_video
.pixel_height_aspect
= 1;
723 // we assume 1:2 for interlaced and 1:1 for deinterlaced video
724 // (this is not really true as it depends on TV standard and
725 // resolution, but it should be enough for start)
726 if( format
->u
.raw_video
.pixel_width_aspect
!= media_raw_video_format::wildcard
.pixel_width_aspect
||
727 format
->u
.raw_video
.pixel_height_aspect
!= media_raw_video_format::wildcard
.pixel_height_aspect
)
729 double ratio
= mode
== C_VIDEO_IN_WEAVE
? 1 : 0.5;
731 if( (float)format
->u
.raw_video
.pixel_width_aspect
/
732 format
->u
.raw_video
.pixel_height_aspect
!= ratio
)
734 DPRINT(( "Unsupported pixel aspect (%d:%d)\n",
735 format
->u
.raw_video
.pixel_width_aspect
,
736 format
->u
.raw_video
.pixel_height_aspect
));
737 return B_MEDIA_BAD_FORMAT
;
740 format
->u
.raw_video
.pixel_width_aspect
= 1;
741 format
->u
.raw_video
.pixel_height_aspect
=
742 mode
== C_VIDEO_IN_WEAVE
? 1 : 2;
749 // verify active range defined as format
751 CRadeonProducer::verifyActiveRange( media_format
*format
)
753 CRadeonRect active_rect
;
755 fVideoIn
.getActiveRange( BeToVideoInStandard( fStandard
), active_rect
);
757 if( format
->u
.raw_video
.first_active
!= media_raw_video_format::wildcard
.first_active
) {
758 if( (int32
)format
->u
.raw_video
.first_active
< 0 ) {
759 DPRINT(( "Unsupported first_active (%d)\n", format
->u
.raw_video
.first_active
));
760 return B_MEDIA_BAD_FORMAT
;
764 // don't care about last_active much - some programs set it to number of
765 // captured lines, which is really something different
766 // (I have the feeling, noone really knows how to use this value properly)
767 if( format
->u
.raw_video
.last_active
!= media_raw_video_format::wildcard
.last_active
) {
768 if( format
->u
.raw_video
.last_active
>= (uint32
)active_rect
.Height() ) {
769 DPRINT(( "Unsupported last_active (%d)\n", format
->u
.raw_video
.last_active
));
770 return B_MEDIA_BAD_FORMAT
;
778 // set active range in format if yet undefined
780 CRadeonProducer::setActiveRange( media_format
*format
)
782 CRadeonRect active_rect
;
784 fVideoIn
.getActiveRange( BeToVideoInStandard( fStandard
), active_rect
);
786 if( format
->u
.raw_video
.first_active
== media_raw_video_format::wildcard
.first_active
)
787 format
->u
.raw_video
.first_active
= 0;
789 if( format
->u
.raw_video
.last_active
== media_raw_video_format::wildcard
.last_active
)
790 format
->u
.raw_video
.last_active
= (uint32
)active_rect
.Height() - 1;
794 // verify requested orientation
796 CRadeonProducer::verifyOrientation( media_format
*format
)
798 if( format
->u
.raw_video
.orientation
!= media_raw_video_format::wildcard
.orientation
) {
799 if( format
->u
.raw_video
.orientation
!= B_VIDEO_TOP_LEFT_RIGHT
) {
800 DPRINT(( "Unsupported orientation (%d)\n", format
->u
.raw_video
.orientation
));
801 return B_MEDIA_BAD_FORMAT
;
809 // set image orientation if yet undefined
811 CRadeonProducer::setOrientation( media_format
*format
)
813 if( format
->u
.raw_video
.orientation
== media_raw_video_format::wildcard
.orientation
)
814 format
->u
.raw_video
.orientation
= B_VIDEO_TOP_LEFT_RIGHT
;
818 // verify requested pixel format
820 CRadeonProducer::verifyPixelFormat( media_format
*format
)
822 if( format
->u
.raw_video
.display
.format
!=
823 media_raw_video_format::wildcard
.display
.format
)
825 switch( format
->u
.raw_video
.display
.format
) {
834 DPRINT(("Unsupported colour space (%x)\n",
835 format
->u
.raw_video
.display
.format
));
836 return B_MEDIA_BAD_FORMAT
;
844 // set pixel format to user-defined default if not set yet
846 CRadeonProducer::setPixelFormat( media_format
*format
)
848 if( format
->u
.raw_video
.display
.format
==
849 media_raw_video_format::wildcard
.display
.format
)
850 format
->u
.raw_video
.display
.format
= (color_space
)fFormat
;
854 Verify video size and set it if undefined.
857 CRadeonProducer::verifySetSize(
858 media_format
*format
, int32 mode
, bool set_bytes_per_row
)
860 CRadeonRect active_rect
;
862 fVideoIn
.getActiveRange( BeToVideoInStandard( fStandard
), active_rect
);
864 // width and height must both be defined, else we define it ourself,
865 // i.e. if the application leaves one of them wildcarded, we
867 if( format
->u
.raw_video
.display
.line_width
!=
868 media_raw_video_format::wildcard
.display
.line_width
&&
869 format
->u
.raw_video
.display
.line_count
!=
870 media_raw_video_format::wildcard
.display
.line_count
)
872 uint32 max_height
= active_rect
.Height();
874 if( mode
!= C_VIDEO_IN_WEAVE
)
877 if( format
->u
.raw_video
.display
.line_width
> (uint32
)active_rect
.Width() ||
878 format
->u
.raw_video
.display
.line_count
> max_height
)
880 DPRINT(("Requested image size is too high (%dx%d)\n",
881 format
->u
.raw_video
.display
.line_width
,
882 format
->u
.raw_video
.display
.line_count
));
883 return B_MEDIA_BAD_FORMAT
;
886 // our format converters do up to 8 pixels at a time (grey8);
887 // to be absolutely sure we don't get trouble there, refuse
888 // any width that is not a multiple of 8
890 if( (format
->u
.raw_video
.display
.line_width
& 7) != 0 ) {
891 DPRINT(( "Request image width is not multiple of 8 (%d)\n",
892 format
->u
.raw_video
.display
.line_width
));
893 return B_MEDIA_BAD_FORMAT
;
897 switch (fResolution
) {
899 format
->u
.raw_video
.display
.line_width
= 640;
900 format
->u
.raw_video
.display
.line_count
= 480;
903 format
->u
.raw_video
.display
.line_width
= 480;
904 format
->u
.raw_video
.display
.line_count
= 360;
907 format
->u
.raw_video
.display
.line_width
= 720;
908 format
->u
.raw_video
.display
.line_count
= 480;
911 format
->u
.raw_video
.display
.line_width
= 720;
912 format
->u
.raw_video
.display
.line_count
= 576;
915 format
->u
.raw_video
.display
.line_width
= 768;
916 format
->u
.raw_video
.display
.line_count
= 576;
919 format
->u
.raw_video
.display
.line_width
= 320;
920 format
->u
.raw_video
.display
.line_count
= 240;
923 format
->u
.raw_video
.display
.line_width
= 160;
924 format
->u
.raw_video
.display
.line_count
= 120;
928 if( format
->u
.raw_video
.display
.line_width
> (uint32
)active_rect
.Width() )
929 format
->u
.raw_video
.display
.line_width
= (uint32
)active_rect
.Width() & ~7;
931 if( format
->u
.raw_video
.display
.line_count
> (uint32
)active_rect
.Height() )
932 format
->u
.raw_video
.display
.line_count
= (uint32
)active_rect
.Height();
934 // BOB and FIELD modes provide only field, which has half height
935 if( mode
!= C_VIDEO_IN_WEAVE
) {
936 if( format
->u
.raw_video
.display
.line_count
> (uint32
)active_rect
.Height() / 2 )
937 format
->u
.raw_video
.display
.line_count
= (uint32
)active_rect
.Height() / 2;
941 if( format
->u
.raw_video
.display
.format
!= media_raw_video_format::wildcard
.display
.format
) {
942 uint32 bytes_per_row
;
944 switch( format
->u
.raw_video
.display
.format
) {
947 format
->u
.raw_video
.display
.line_width
* 4;
954 format
->u
.raw_video
.display
.line_width
* 2;
959 format
->u
.raw_video
.display
.line_width
;
962 if( format
->u
.raw_video
.display
.bytes_per_row
!=
963 media_raw_video_format::wildcard
.display
.bytes_per_row
)
965 if( format
->u
.raw_video
.display
.bytes_per_row
< bytes_per_row
) {
966 DPRINT(( "Requested bytes per row are too small",
967 format
->u
.raw_video
.display
.bytes_per_row
));
968 return B_MEDIA_BAD_FORMAT
;
970 } else if( set_bytes_per_row
)
971 format
->u
.raw_video
.display
.bytes_per_row
= bytes_per_row
;
979 // verify "offset" parameters of format
981 CRadeonProducer::verifyFormatOffsets( media_format
*format
)
983 if( format
->u
.raw_video
.display
.pixel_offset
!=
984 media_raw_video_format::wildcard
.display
.pixel_offset
&&
985 format
->u
.raw_video
.display
.pixel_offset
!= 0 )
987 DPRINT(( "Requested pixel offset is not zero" ));
988 return B_MEDIA_BAD_FORMAT
;
991 if( format
->u
.raw_video
.display
.line_offset
!=
992 media_raw_video_format::wildcard
.display
.line_offset
&&
993 format
->u
.raw_video
.display
.line_offset
!= 0 )
995 DPRINT(( "Requested line offset is not zero" ));
996 return B_MEDIA_BAD_FORMAT
;
1003 // set "offset" parameters of format if not set yet
1005 CRadeonProducer::setFormatOffsets( media_format
*format
)
1007 if( format
->u
.raw_video
.display
.pixel_offset
==
1008 media_raw_video_format::wildcard
.display
.pixel_offset
)
1009 format
->u
.raw_video
.display
.pixel_offset
= 0;
1011 if( format
->u
.raw_video
.display
.line_offset
==
1012 media_raw_video_format::wildcard
.display
.line_offset
)
1013 format
->u
.raw_video
.display
.line_offset
= 0;
1017 // verify "flags" parameter of format
1019 CRadeonProducer::verifyFormatFlags( media_format
*format
)
1021 if( format
->u
.raw_video
.display
.flags
!=
1022 media_raw_video_format::wildcard
.display
.flags
&&
1023 format
->u
.raw_video
.display
.flags
!= 0 )
1025 DPRINT(( "Requested display flags are not zero" ));
1026 return B_MEDIA_BAD_FORMAT
;
1033 // set "flags" parameter of format if not set yet
1035 CRadeonProducer::setFormatFlags( media_format
*format
)
1037 if( format
->u
.raw_video
.display
.flags
==
1038 media_raw_video_format::wildcard
.display
.flags
)
1039 format
->u
.raw_video
.display
.flags
= 0;
1044 * Fill out all wildcards in a format descriptor.
1047 CRadeonProducer::finalizeFormat( media_format
*format
)
1049 if (format
->type
!= B_MEDIA_RAW_VIDEO
)
1050 return B_MEDIA_BAD_FORMAT
;
1054 res
= verifySetMode( format
);
1058 int32 mode
= extractCaptureMode( format
);
1060 res
= verifyActiveRange( format
);
1064 setActiveRange( format
);
1066 res
= verifyOrientation( format
);
1070 res
= verifySetPixelAspect( format
);
1074 res
= verifyPixelFormat( format
);
1078 setPixelFormat( format
);
1080 res
= verifySetSize( format
, mode
, true );
1084 res
= verifyFormatOffsets( format
);
1088 setFormatOffsets( format
);
1090 res
= verifyFormatFlags( format
);
1094 setFormatFlags( format
);
1100 * Someone has no idea what format we usually provide and asks us.
1102 * It's not really clear whether we are allowed to return wildcards.
1105 CRadeonProducer::FormatSuggestionRequested(
1106 media_type type
, int32 quality
, media_format
*format
)
1108 DPRINT(("CRadeonProducer::FormatSuggestionRequested()\n"));
1110 if (type
!= B_MEDIA_RAW_VIDEO
)
1111 return B_MEDIA_BAD_FORMAT
;
1115 format
->type
= B_MEDIA_RAW_VIDEO
;
1117 format
->u
.raw_video
= media_raw_video_format::wildcard
;
1119 finalizeFormat( format
);
1126 Initial format proposal as part of a connection establishment.
1128 First, the application defines a format with many wildcards in it;
1129 this format is passed to us, so we can restrict it if necessary;
1130 we should leave as many wildcards as possible, because in the next
1131 step the consumer is asked, and he will not be happy if he has no choice left .
1134 CRadeonProducer::FormatProposal(const media_source
&output
, media_format
*format
)
1138 DPRINT(("CRadeonProducer::FormatProposal()\n"));
1140 if( format
== NULL
)
1143 if( output
!= fOutput
.source
)
1144 return B_MEDIA_BAD_SOURCE
;
1146 string_for_format(*format
, buffer
, sizeof(buffer
));
1148 DPRINT(("CRadeonProducer::FormatProposal() - in=%s\n", buffer
));
1150 if( format
->type
== B_MEDIA_NO_TYPE
) {
1151 // if there is not even a type, set raw video
1152 format
->type
= B_MEDIA_RAW_VIDEO
;
1153 format
->u
.raw_video
= media_raw_video_format::wildcard
;
1156 if (format
->type
!= B_MEDIA_RAW_VIDEO
)
1157 return B_MEDIA_BAD_FORMAT
;
1161 // first, choose capture mode, so we know the maximum video size
1162 res
= verifySetMode( format
);
1166 int32 mode
= extractCaptureMode( format
);
1168 res
= verifyActiveRange( format
);
1172 res
= verifyOrientation( format
);
1176 setOrientation( format
);
1178 // simple aspect calculation: we always use 1:1, so setting this is easy
1179 res
= verifySetPixelAspect( format
);
1183 res
= verifyPixelFormat( format
);
1187 // if we don't set it, the consumer usually chooses a stupid format
1188 setPixelFormat( format
);
1190 // verify size and set if if undefined;
1191 // do that now, else the consumer will set it (making the defaults
1192 // set via preferences useless)
1193 // leave bytes_per_lines untouched, though
1194 // (we don't really care but the consumer may have some alignment restrictions)
1195 res
= verifySetSize( format
, mode
, false );
1199 res
= verifyFormatOffsets( format
);
1203 res
= verifyFormatFlags( format
);
1207 string_for_format(*format
, buffer
, sizeof(buffer
));
1209 DPRINT(("CRadeonProducer::FormatProposal() - out=%s\n", buffer
));
1215 CRadeonProducer::FormatChangeRequested(const media_source
&source
,
1216 const media_destination
&destination
, media_format
*io_format
,
1217 int32
*_deprecated_
)
1219 DPRINT(("CRadeonProducer::FormatChangeRequested()\n"));
1221 TOUCH(destination
); TOUCH(io_format
); TOUCH(_deprecated_
);
1222 if (source
!= fOutput
.source
)
1223 return B_MEDIA_BAD_SOURCE
;
1229 CRadeonProducer::GetNextOutput(int32
*cookie
, media_output
*out_output
)
1231 DPRINT(("CRadeonProducer::GetNextOutput()\n"));
1239 *out_output
= fOutput
;
1245 CRadeonProducer::DisposeOutputCookie(int32 cookie
)
1247 DPRINT(("CRadeonProducer::DisposeOutputCookie()\n"));
1255 CRadeonProducer::SetBufferGroup(const media_source
&for_source
,
1256 BBufferGroup
*group
)
1258 DPRINT(("CRadeonProducer::SetBufferGroup()\n"));
1260 if( for_source
!= fOutput
.source
)
1261 return B_MEDIA_BAD_SOURCE
;
1263 if( group
!= NULL
) {
1264 delete fBufferGroup
;
1265 fBufferGroup
= group
;
1272 CRadeonProducer::VideoClippingChanged(const media_source
&for_source
,
1273 int16 num_shorts
, int16
*clip_data
,
1274 const media_video_display_info
&display
, int32
*_deprecated_
)
1276 DPRINT(("CRadeonProducer::VideoClippingChanged()\n"));
1278 TOUCH(for_source
); TOUCH(num_shorts
); TOUCH(clip_data
);
1279 TOUCH(display
); TOUCH(_deprecated_
);
1285 CRadeonProducer::GetLatency(bigtime_t
*out_latency
)
1287 DPRINT(("CRadeonProducer::GetLatency()\n"));
1289 // delay is one frame for capturing, a scheduling latency, the
1290 // DMA copying, the format conversion and the output nodes latency;
1291 // scheduling, DMA copying and format conversion is summed up in
1292 // fProcessingLatency
1293 bigtime_t capture_latency
= (bigtime_t
)(1000000.0 / fOutput
.format
.u
.raw_video
.field_rate
);
1295 // HACK: (see HandleHardware())
1296 // to be compatible to existing software, we write the ending time of
1297 // capture instead of the beginning time into buffers, thus we
1298 // have no capture delay
1299 capture_latency
= 0;
1301 bigtime_t buffer_latency
= fProcessingLatency
;
1302 BBufferProducer::GetLatency( &buffer_latency
);
1304 *out_latency
= SchedulingLatency() + capture_latency
+ fProcessingLatency
+
1307 DPRINT(("latency=%lld\n", *out_latency
));
1314 CRadeonProducer::PrepareToConnect(const media_source
&source
,
1315 const media_destination
&destination
, media_format
*format
,
1316 media_source
*out_source
, char *out_name
)
1318 DPRINT(("CRadeonProducer::PrepareToConnect()\n"));
1320 PRINTF(1, ("PrepareToConnect() %ldx%ld\n", \
1321 format
->u
.raw_video
.display
.line_width
, \
1322 format
->u
.raw_video
.display
.line_count
));
1324 if (source
!= fOutput
.source
) {
1325 DPRINT(("bad source\n"));
1326 return B_MEDIA_BAD_SOURCE
;
1329 if (fOutput
.destination
!= media_destination::null
) {
1330 DPRINT(("already connected\n"));
1331 return B_MEDIA_ALREADY_CONNECTED
;
1335 string_for_format(*format
, buffer
, sizeof(buffer
));
1336 DPRINT(("CRadeonProducer::PrepareToConnect() - in=%s\n", buffer
));
1338 status_t res
= finalizeFormat( format
);
1342 *out_source
= fOutput
.source
;
1343 strcpy(out_name
, fOutput
.name
);
1345 string_for_format(*format
, buffer
, sizeof(buffer
));
1346 DPRINT(("CRadeonProducer::PrepareToConnect() - out=%s\n", buffer
));
1348 // reserve connection
1349 fOutput
.destination
= destination
;
1351 DPRINT(("finished\n"));
1357 CRadeonProducer::setDefaultBufferGroup()
1359 DPRINT(("CRadeonProducer::setDefaultBufferGroup()\n"));
1360 /*delete fBufferGroup;
1361 fBufferGroup = NULL;*/
1362 if( fBufferGroup
!= NULL
) {
1363 DPRINT(("Buffer already set\n"));
1367 fBufferGroup
= new BBufferGroup(
1368 fOutput
.format
.u
.raw_video
.display
.bytes_per_row
*
1369 fOutput
.format
.u
.raw_video
.display
.line_count
,
1370 3, B_ANY_ADDRESS
, B_FULL_LOCK
);
1372 if (fBufferGroup
->InitCheck() < B_OK
) {
1373 delete fBufferGroup
;
1374 fBufferGroup
= NULL
;
1380 CRadeonProducer::startCapturing()
1382 if( RunState() != BMediaEventLooper::B_STARTED
||
1383 fOutput
.destination
== media_destination::null
)
1386 fVideoIn
.SetChannel(fTuner
, C_VIDEO_IN_NTSC
); // was hardcoded to NTSC
1387 fVideoIn
.SetBrightness(fBrightness
);
1388 fVideoIn
.SetContrast(fContrast
);
1389 fVideoIn
.SetSaturation(fSaturation
);
1390 fVideoIn
.SetHue(fHue
);
1391 fVideoIn
.SetSharpness(fSharpness
);
1393 fVideoIn
.Start(video_in_source(fSource
), BeToVideoInStandard( fStandard
),
1394 video_in_capture_mode(fCurMode
),
1395 fOutput
.format
.u
.raw_video
.display
.line_width
,
1396 fOutput
.format
.u
.raw_video
.display
.line_count
);
1399 tmp_buffer
= (char *)malloc(
1400 fOutput
.format
.u
.raw_video
.display
.bytes_per_row
*
1401 fOutput
.format
.u
.raw_video
.display
.line_count
);
1405 bigtime_t capture_time
;
1407 // do a real capturing to prime everything
1409 tmp_buffer
!= NULL
? fOutput
.format
.u
.raw_video
.display
.format
: B_NO_COLOR_SPACE
,
1411 fOutput
.format
.u
.raw_video
.display
.bytes_per_row
* fOutput
.format
.u
.raw_video
.display
.line_count
,
1412 fOutput
.format
.u
.raw_video
.display
.bytes_per_row
,
1413 &field_sequence
, &field_number
, &capture_time
);
1415 // capture some frames to be sure there are no pending buffers;
1416 // discard captured data to safe time (we want to catch up and not fall behind)
1417 for( int i
= 0; i
< 3; ++i
) {
1421 fOutput
.format
.u
.raw_video
.display
.bytes_per_row
* fOutput
.format
.u
.raw_video
.display
.line_count
,
1422 fOutput
.format
.u
.raw_video
.display
.bytes_per_row
,
1423 &field_sequence
, &field_number
, &capture_time
);
1425 DPRINT(("Captured: %lld, current: %lld\n", capture_time
, system_time() ));
1428 // do a real capturing to see how long it takes until the
1429 // buffer is ready, i.e. including DMA and colour conversion
1431 tmp_buffer
!= NULL
? fOutput
.format
.u
.raw_video
.display
.format
: B_NO_COLOR_SPACE
,
1433 fOutput
.format
.u
.raw_video
.display
.bytes_per_row
* fOutput
.format
.u
.raw_video
.display
.line_count
,
1434 fOutput
.format
.u
.raw_video
.display
.bytes_per_row
,
1435 &field_sequence
, &field_number
, &capture_time
);
1437 DPRINT(("Captured: %lld, current: %lld\n", capture_time
, system_time() ));
1439 // now we know our internal latency
1440 fProcessingLatency
= system_time() - capture_time
;
1442 DPRINT(("Processing latency: %dµs\n", fProcessingLatency
));
1444 // store field sequence to start with zero
1445 // (capture-internal field sequence always counts up)
1446 fFieldSequenceBase
= field_sequence
;
1448 if( tmp_buffer
!= NULL
)
1451 // tell latence MediaEventLooper so it can schedule events properly ahead
1452 bigtime_t total_latency
;
1454 GetLatency( &total_latency
);
1455 SetEventLatency( total_latency
);
1457 // Create the buffer group
1458 setDefaultBufferGroup();
1460 //fUsedBufferGroup = fBufferGroup;
1462 // schedule a capture event after one field's time
1463 RealTimeQueue()->FlushEvents( 0, BTimedEventQueue::B_ALWAYS
, true, BTimedEventQueue::B_HARDWARE
);
1465 media_timed_event
event(
1466 capture_time
+ 1000000 / fOutput
.format
.u
.raw_video
.field_rate
,
1467 BTimedEventQueue::B_HARDWARE
);
1469 RealTimeQueue()->AddEvent(event
);
1473 CRadeonProducer::Connect(status_t error
, const media_source
&source
,
1474 const media_destination
&destination
, const media_format
&format
,
1477 // we even get called if consumer reported error in AcceptFormat;
1478 // in this case, we must release the source already reserved by
1480 if( error
!= B_OK
) {
1481 DPRINT(( "Connect: Consumer returned error (%s) - releasing source",
1482 strerror( error
)));
1483 fOutput
.destination
= media_destination::null
;
1487 if( source
!= fOutput
.source
) {
1488 DPRINT(( "Connect: Wrong source specified\n"));
1492 fOutput
.destination
= destination
;
1493 fOutput
.format
= format
;
1494 fCurMode
= extractCaptureMode( &format
);
1497 string_for_format(format
, buffer
, sizeof(buffer
));
1499 DPRINT(("CRadeonProducer::Connect() - %s\n", buffer
));
1501 strcpy(io_name
, fOutput
.name
);
1505 DPRINT(("CRadeonProducer::Connect() done\n"));
1509 CRadeonProducer::Disconnect(const media_source
&source
,
1510 const media_destination
&destination
)
1512 DPRINT(("Disconnect()\n"));
1514 if( source
!= fOutput
.source
|| destination
!= fOutput
.destination
) {
1515 DPRINT(("Disconnect: Bad source and/or destination\n"));
1519 fOutput
.destination
= media_destination::null
;
1521 delete fBufferGroup
;
1522 fBufferGroup
= NULL
;
1526 RealTimeQueue()->FlushEvents( 0, BTimedEventQueue::B_ALWAYS
, true, BTimedEventQueue::B_HARDWARE
);
1528 // reset format to get rid of any connection left-overs
1529 fOutput
.format
.type
= B_MEDIA_RAW_VIDEO
;
1530 fOutput
.format
.u
.raw_video
= media_raw_video_format::wildcard
;
1532 DPRINT(("Disconnect() done\n"));
1536 CRadeonProducer::LateNoticeReceived(const media_source
&source
,
1537 bigtime_t how_much
, bigtime_t performance_time
)
1539 DPRINT(("CRadeonProducer::LateNoticeReceived()\n"));
1541 TOUCH(source
); TOUCH(how_much
); TOUCH(performance_time
);
1545 CRadeonProducer::EnableOutput(const media_source
&source
, bool enabled
,
1546 int32
*_deprecated_
)
1548 DPRINT(("CRadeonProducer::EnableOutput()\n"));
1550 TOUCH(_deprecated_
);
1552 if (source
!= fOutput
.source
)
1559 CRadeonProducer::SetPlayRate(int32 numer
, int32 denom
)
1561 DPRINT(("CRadeonProducer::SetPlayRate()\n"));
1563 TOUCH(numer
); TOUCH(denom
);
1569 CRadeonProducer::AdditionalBufferRequested(const media_source
&source
,
1570 media_buffer_id prev_buffer
, bigtime_t prev_time
,
1571 const media_seek_tag
*prev_tag
)
1573 DPRINT(("CRadeonProducer::AdditionalBufferRequested()\n"));
1575 TOUCH(source
); TOUCH(prev_buffer
); TOUCH(prev_time
); TOUCH(prev_tag
);
1579 CRadeonProducer::LatencyChanged(const media_source
&source
,
1580 const media_destination
&destination
, bigtime_t new_latency
,
1583 DPRINT(("CRadeonProducer::LatencyChanged()\n"));
1584 BBufferProducer::LatencyChanged( source
, destination
, new_latency
, flags
);
1592 CRadeonProducer::GetParameterValue(
1593 int32 id
, bigtime_t
*last_change
, void *value
, size_t *size
)
1595 DPRINT(("CRadeonProducer::GetParameterValue(%d)\n", id
));
1599 *last_change
= fSourceLastChange
;
1600 *size
= sizeof(fSource
);
1601 *((uint32
*) value
) = fSource
;
1604 *last_change
= fStandardLastChange
;
1605 *size
= sizeof(fStandard
);
1606 *((uint32
*) value
) = fStandard
;
1609 *last_change
= fModeLastChange
;
1610 *size
= sizeof(fMode
);
1611 *((uint32
*) value
) = fMode
;
1614 *last_change
= fFormatLastChange
;
1615 *size
= sizeof(fFormat
);
1616 *((uint32
*) value
) = fFormat
;
1619 *last_change
= fResolutionLastChange
;
1620 *size
= sizeof(fResolution
);
1621 *((uint32
*) value
) = fResolution
;
1624 *last_change
= fTunerLastChange
;
1625 *size
= sizeof(fTuner
);
1626 *((uint32
*) value
) = fTuner
;
1629 *last_change
= fBrightnessLastChange
;
1630 *size
= sizeof(fBrightness
);
1631 *((float *) value
) = fBrightness
;
1634 *last_change
= fContrastLastChange
;
1635 *size
= sizeof(fContrast
);
1636 *((float *) value
) = fContrast
;
1639 *last_change
= fSaturationLastChange
;
1640 *size
= sizeof(fSaturation
);
1641 *((float *) value
) = fSaturation
;
1644 *last_change
= fHueLastChange
;
1645 *size
= sizeof(fHue
);
1646 *((float *) value
) = fHue
;
1649 *last_change
= fSharpnessLastChange
;
1650 *size
= sizeof(fSharpness
);
1651 *((float *) value
) = fSharpness
;
1654 DPRINT(("Unknown parameter\n"));
1663 * Change video format instantly.
1665 * Used when user changes a settings that affect the video format.
1666 * The new format must be the current format with some values
1667 * replaced with wildcards. Don't put too many wildcards:
1668 * some settings (like video size) are normally chosen by the
1669 * application, so don't use this function as a secret override.
1672 CRadeonProducer::instantFormatChange( media_format
*new_format
)
1674 if( fOutput
.destination
== media_destination::null
)
1677 if( finalizeFormat( new_format
) != B_OK
) {
1678 DPRINT(("Current format does not allow to change interlace mode on-the-fly\n"));
1682 if( ChangeFormat( fOutput
.source
, fOutput
.destination
, new_format
) != B_OK
) {
1683 DPRINT(("Consumer does not allow to change interlace mode instantly\n"));
1687 fOutput
.format
= *new_format
;
1688 fCurMode
= extractCaptureMode( new_format
);
1695 CRadeonProducer::SetParameterValue(
1696 int32 id
, bigtime_t when
, const void *value
, size_t size
)
1698 DPRINT(("CRadeonProducer::SetParameterValue()\n"));
1700 if (!value
|| size
!= sizeof(uint32
))
1705 if (*((const int32
*) value
) == fSource
)
1707 fSource
= *((const uint32
*) value
);
1708 fSourceLastChange
= when
;
1710 // if there is no tuner, force composite input
1711 // (eXposer sets source manually to tuner, even if there is none)
1712 // if there is no tuner, it isn't in the list and can't be picked!
1713 //if( (fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) == 0 )
1714 // fSource = C_VIDEO_IN_COMPOSITE;
1718 if (*((const int32
*) value
) == fStandard
)
1721 fStandard
= BeToVideoInStandard( *((const int32
*) value
) );
1723 fStandardLastChange
= when
;
1725 media_format new_format
= fOutput
.format
;
1727 new_format
.u
.raw_video
.field_rate
= media_raw_video_format::wildcard
.field_rate
;
1728 new_format
.u
.raw_video
.interlace
= media_raw_video_format::wildcard
.interlace
;
1729 new_format
.u
.raw_video
.pixel_width_aspect
= media_raw_video_format::wildcard
.pixel_width_aspect
;
1730 new_format
.u
.raw_video
.pixel_height_aspect
= media_raw_video_format::wildcard
.pixel_height_aspect
;
1731 new_format
.u
.raw_video
.first_active
= media_raw_video_format::wildcard
.first_active
;
1732 new_format
.u
.raw_video
.last_active
= media_raw_video_format::wildcard
.last_active
;
1734 instantFormatChange( &new_format
);
1737 if (*((const int32
*) value
) == fMode
)
1740 fMode
= *((const uint32
*) value
);
1741 fModeLastChange
= when
;
1743 media_format new_format
= fOutput
.format
;
1745 new_format
.u
.raw_video
.field_rate
= media_raw_video_format::wildcard
.field_rate
;
1746 new_format
.u
.raw_video
.interlace
= media_raw_video_format::wildcard
.interlace
;
1747 new_format
.u
.raw_video
.pixel_width_aspect
= media_raw_video_format::wildcard
.pixel_width_aspect
;
1748 new_format
.u
.raw_video
.pixel_height_aspect
= media_raw_video_format::wildcard
.pixel_height_aspect
;
1750 instantFormatChange( &new_format
);
1754 if (*((const int32
*) value
) == fFormat
)
1756 fFormat
= *((const uint32
*) value
);
1757 fFormatLastChange
= when
;
1759 media_format new_format
= fOutput
.format
;
1761 new_format
.u
.raw_video
.display
.format
= media_raw_video_format::wildcard
.display
.format
;
1762 new_format
.u
.raw_video
.display
.bytes_per_row
= media_raw_video_format::wildcard
.display
.bytes_per_row
;
1764 instantFormatChange( &new_format
);
1767 if (*((const int32
*) value
) == fResolution
)
1769 fResolution
= *((const uint32
*) value
);
1770 fResolutionLastChange
= when
;
1771 // no live update - see instantFormatChange()
1774 if (*((const int32
*) value
) == fTuner
)
1776 fTuner
= *((const uint32
*) value
);
1777 fTunerLastChange
= when
;
1778 fVideoIn
.SetChannel(fTuner
, C_VIDEO_IN_NTSC
); // was hardcoded to NTSC
1781 if (*((const float *) value
) == fBrightness
)
1783 fBrightness
= (int32
)*((const float *) value
);
1784 fBrightnessLastChange
= when
;
1785 fVideoIn
.SetBrightness(fBrightness
);
1788 if (*((const float *) value
) == fContrast
)
1790 fContrast
= (int32
)*((const float *) value
);
1791 fContrastLastChange
= when
;
1792 fVideoIn
.SetContrast(fContrast
);
1795 if (*((const float *) value
) == fSaturation
)
1797 fSaturation
= (int32
)*((const float *) value
);
1798 fSaturationLastChange
= when
;
1799 fVideoIn
.SetSaturation(fSaturation
);
1802 if (*((const float *) value
) == fHue
)
1804 fHue
= (int32
)*((const float *) value
);
1805 fHueLastChange
= when
;
1806 fVideoIn
.SetHue(fHue
);
1809 if (*((const float *) value
) == fSharpness
)
1811 fSharpness
= (int32
)*((const float *) value
);
1812 fSharpnessLastChange
= when
;
1813 fVideoIn
.SetSharpness(fSharpness
);
1819 BroadcastNewParameterValue(when
, id
, const_cast<void *>(value
), sizeof(uint32
));
1823 CRadeonProducer::StartControlPanel(BMessenger
*out_messenger
)
1825 return BControllable::StartControlPanel(out_messenger
);
1828 status_t
CRadeonProducer::AddInt32(
1829 BMessage
*msg
, EOptions option
, int32 value
)
1833 *(int32
*)name
= option
;
1836 return msg
->AddInt32( name
, value
);
1840 CRadeonProducer::GetConfiguration( BMessage
*out
)
1844 if( (res
= AddInt32( out
, P_SOURCE
, fSource
)) != B_OK
||
1845 (res
= AddInt32( out
, P_STANDARD
, BeToVideoInStandard( fStandard
))) != B_OK
||
1846 (res
= AddInt32( out
, P_MODE
, fMode
)) != B_OK
||
1847 (res
= AddInt32( out
, P_FORMAT
, fFormat
)) != B_OK
||
1848 (res
= AddInt32( out
, P_RESOLUTION
, fResolution
)) != B_OK
||
1849 (res
= AddInt32( out
, P_TUNER
, fTuner
)) != B_OK
||
1850 (res
= AddInt32( out
, P_BRIGHTNESS
, fBrightness
)) != B_OK
||
1851 (res
= AddInt32( out
, P_CONTRAST
, fContrast
)) != B_OK
||
1852 (res
= AddInt32( out
, P_SATURATION
, fSaturation
)) != B_OK
||
1853 (res
= AddInt32( out
, P_HUE
, fHue
)) != B_OK
||
1854 (res
= AddInt32( out
, P_SHARPNESS
, fSharpness
)) != B_OK
)
1864 CRadeonProducer::HandleStart(bigtime_t performance_time
)
1866 /* Start producing frames, even if the output hasn't been connected yet. */
1867 DPRINT(("CRadeonProducer::HandleStart()\n"));
1869 if( RunState() != BMediaEventLooper::B_STOPPED
) {
1870 DPRINT(("already running\n"));
1874 SetRunState( BMediaEventLooper::B_STARTED
);
1880 CRadeonProducer::HandleStop(void)
1882 DPRINT(("CRadeonProducer::HandleStop()\n"));
1886 // discard pending capture event
1887 RealTimeQueue()->FlushEvents( 0, BTimedEventQueue::B_ALWAYS
, true, BTimedEventQueue::B_HARDWARE
);
1891 CRadeonProducer::HandleTimeWarp(bigtime_t performance_time
)
1893 DPRINT(("CRadeonProducer::HandleTimeWarp()\n"));
1897 CRadeonProducer::HandleSeek(bigtime_t performance_time
)
1899 DPRINT(("CRadeonProducer::HandleSeek()\n"));
1903 CRadeonProducer::captureField( bigtime_t
*capture_time
)
1905 *capture_time
= system_time();
1907 // don't capture if output is disabled
1911 BBuffer
*buffer
= fBufferGroup
->RequestBuffer(
1912 fOutput
.format
.u
.raw_video
.display
.bytes_per_row
*
1913 fOutput
.format
.u
.raw_video
.display
.line_count
, 0LL);
1916 DPRINT(( "No buffer\n" ));
1920 media_header
*h
= buffer
->Header();
1921 h
->type
= B_MEDIA_RAW_VIDEO
;
1922 h
->time_source
= TimeSource()->ID();
1923 h
->size_used
= fOutput
.format
.u
.raw_video
.display
.bytes_per_row
*
1924 fOutput
.format
.u
.raw_video
.display
.line_count
;
1928 h
->u
.raw_video
.field_gamma
= 1.0;
1929 h
->u
.raw_video
.pulldown_number
= 0;
1930 h
->u
.raw_video
.first_active_line
= fOutput
.format
.u
.raw_video
.first_active
;
1931 h
->u
.raw_video
.line_count
= fOutput
.format
.u
.raw_video
.display
.line_count
;
1936 int dropped
=fVideoIn
.Capture(
1937 fOutput
.format
.u
.raw_video
.display
.format
,
1939 fOutput
.format
.u
.raw_video
.display
.bytes_per_row
* fOutput
.format
.u
.raw_video
.display
.line_count
,
1940 fOutput
.format
.u
.raw_video
.display
.bytes_per_row
,
1945 // HACK: store end instead of start time
1946 // obviously, the _start_ time of a frame is always in the past by one
1947 // frame; unfortunately, programs like stamptv expect the start time to
1948 // be in the present, else they drop the frame; therefore, we write the
1949 // _end_ time into the start time field, and everyone is happy (though
1950 // the time is wrong)
1951 // this leads to many tweaks in the code!
1952 h
->start_time
= TimeSource()->PerformanceTimeFor( *capture_time
);
1954 h
->u
.raw_video
.field_sequence
= field_sequence
- fFieldSequenceBase
;
1955 h
->u
.raw_video
.field_number
= field_number
;
1958 PRINT(("%d frames dropped\n", dropped
-1));
1961 if (SendBuffer(buffer
, fOutput
.destination
) < B_OK
) {
1962 PRINTF(-1, ("FrameGenerator: Error sending buffer\n"));
1968 CRadeonProducer::HandleHardware()
1970 bigtime_t capture_time
;
1974 if( RunState() != BMediaEventLooper::B_STARTED
)
1977 captureField( &capture_time
);
1979 // generate next event after next field
1980 media_timed_event
event(
1981 capture_time
+ 1000000 / fOutput
.format
.u
.raw_video
.field_rate
,
1982 BTimedEventQueue::B_HARDWARE
);
1984 RealTimeQueue()->AddEvent(event
);