1 /******************************************************************************
3 / File: RadeonAddOn.cpp
5 / Description: ATI Radeon Video Capture Media AddOn for BeOS.
7 / Copyright 2001, Carlos Hasan
9 *******************************************************************************/
11 #include <support/Autolock.h>
12 #include <media/MediaFormats.h>
13 #include <Directory.h>
22 #include <storage/FindDirectory.h>
25 #include "RadeonAddOn.h"
26 #include "RadeonProducer.h"
28 #define DPRINT(args) { PRINT(("\x1b[0;30;35m")); PRINT(args); PRINT(("\x1b[0;30;47m")); }
30 CRadeonPlug::CRadeonPlug( CRadeonAddOn
*aaddon
, const BPath
&adev_path
, int aid
)
31 : addon( aaddon
), dev_path( adev_path
), id( aid
), node( NULL
)
33 fFlavorInfo
.name
= const_cast<char *>("Radeon In");
34 fFlavorInfo
.info
= const_cast<char *>("Radeon Video In Media Node");
35 fFlavorInfo
.kinds
= B_BUFFER_PRODUCER
| B_CONTROLLABLE
| B_PHYSICAL_INPUT
;
36 fFlavorInfo
.flavor_flags
= 0;
37 fFlavorInfo
.internal_id
= aid
;
38 fFlavorInfo
.possible_count
= 1;
40 fFlavorInfo
.in_format_count
= 0;
41 fFlavorInfo
.in_format_flags
= 0;
42 fFlavorInfo
.in_formats
= NULL
;
44 fFlavorInfo
.out_format_count
= 4;
45 //fFlavorInfo.out_format_count = 1;
46 fFlavorInfo
.out_format_flags
= 0;
48 fMediaFormat
[0].type
= B_MEDIA_RAW_VIDEO
;
49 fMediaFormat
[0].u
.raw_video
= media_raw_video_format::wildcard
;
50 fMediaFormat
[0].u
.raw_video
.interlace
= 1;
51 fMediaFormat
[0].u
.raw_video
.display
.format
= B_RGB32
;
53 fMediaFormat
[1].type
= B_MEDIA_RAW_VIDEO
;
54 fMediaFormat
[1].u
.raw_video
= media_raw_video_format::wildcard
;
55 fMediaFormat
[1].u
.raw_video
.interlace
= 1;
56 fMediaFormat
[1].u
.raw_video
.display
.format
= B_RGB16
;
58 fMediaFormat
[2].type
= B_MEDIA_RAW_VIDEO
;
59 fMediaFormat
[2].u
.raw_video
= media_raw_video_format::wildcard
;
60 fMediaFormat
[2].u
.raw_video
.interlace
= 1;
61 fMediaFormat
[2].u
.raw_video
.display
.format
= B_RGB15
;
63 fMediaFormat
[3].type
= B_MEDIA_RAW_VIDEO
;
64 fMediaFormat
[3].u
.raw_video
= media_raw_video_format::wildcard
;
65 fMediaFormat
[3].u
.raw_video
.interlace
= 1;
66 fMediaFormat
[3].u
.raw_video
.display
.format
= B_YCbCr422
;
68 /*fMediaFormat[0].type = B_MEDIA_RAW_VIDEO;
69 fMediaFormat[0].u.raw_video = media_raw_video_format::wildcard;
70 fMediaFormat[0].u.raw_video.interlace = 1;
71 fMediaFormat[0].u.raw_video.display.format = B_YCbCr422;*/
73 fFlavorInfo
.out_formats
= fMediaFormat
;
79 CRadeonPlug::getSettingsPath()
83 if( find_directory( B_USER_CONFIG_DIRECTORY
, &path
) != B_OK
)
86 path
.Append( "settings/Media/RadeonIn" );
88 create_directory( path
.Path(), 755 );
92 id_string
<< "settings" << id
;
94 path
.Append( id_string
.String() );
100 CRadeonPlug::writeSettings( BMessage
*new_settings
)
102 BMessage cur_settings
;
104 // if new_settings are provided, use them; else, ask node for settings
105 // (needed during shutdown where node cannot reply anymore)
106 if( new_settings
!= NULL
) {
107 cur_settings
= *new_settings
;
113 if( addon
->GetConfigurationFor( node
, &cur_settings
) != B_OK
)
117 BMallocIO old_settings_flat
, new_settings_flat
;
119 settings
.Flatten( &old_settings_flat
);
120 cur_settings
.Flatten( &new_settings_flat
);
122 if( old_settings_flat
.BufferLength() == new_settings_flat
.BufferLength() &&
123 memcmp( old_settings_flat
.Buffer(), new_settings_flat
.Buffer(), old_settings_flat
.BufferLength() ) == 0 )
126 settings
= cur_settings
;
128 BPath settings_path
= getSettingsPath();
130 BFile
file( settings_path
.Path(), B_WRITE_ONLY
| B_CREATE_FILE
);
132 settings
.Flatten( &file
);
136 CRadeonPlug::readSettings()
138 BPath settings_path
= getSettingsPath();
140 BFile
file( settings_path
.Path(), B_READ_ONLY
);
142 settings
.Unflatten( &file
);
146 CRadeonAddOn::CRadeonAddOn(image_id imid
)
148 settings_thread( -1 ), settings_thread_sem( -1 )
150 DPRINT(("CRadeonAddOn::CRadeonAddOn()\n"));
152 fInitStatus
= B_NO_INIT
;
154 if( RecursiveScan( "/dev/video/radeon" ) != B_OK
)
157 if( (settings_thread_sem
= create_sem( 0, "Radeon In settings" )) < 0 )
160 if( INIT_BEN( plug_lock
, "Radeon device list" ) < 0 )
163 if( (settings_thread
= spawn_thread(
164 settings_writer
, "Radeon In settings", B_LOW_PRIORITY
, this )) < 0 )
167 resume_thread( settings_thread
);
172 CRadeonAddOn::~CRadeonAddOn()
176 DPRINT(("CRadeonAddOn::~CRadeonAddOn()\n"));
178 release_sem( settings_thread_sem
);
179 wait_for_thread( settings_thread
, &dummy
);
181 delete_sem( settings_thread_sem
);
183 for( int32 i
= 0; i
< fDevices
.CountItems(); ++i
) {
184 CRadeonPlug
*plug
= (CRadeonPlug
*)fDevices
.ItemAt(i
);
189 DELETE_BEN( plug_lock
);
194 CRadeonAddOn::InitCheck(const char **out_failure_text
)
196 DPRINT(("CRadeonAddOn::InitCheck()\n"));
198 if (fInitStatus
< B_OK
) {
199 *out_failure_text
= "Unknown error";
207 CRadeonAddOn::settings_writer( void *param
)
209 ((CRadeonAddOn
*)param
)->settingsWriter();
214 CRadeonAddOn::writeSettings()
216 ACQUIRE_BEN( plug_lock
);
218 for( int32 i
= 0; i
< fDevices
.CountItems(); ++i
) {
219 CRadeonPlug
*plug
= (CRadeonPlug
*)fDevices
.ItemAt(i
);
221 plug
->writeSettings( NULL
);
224 RELEASE_BEN( plug_lock
);
228 CRadeonAddOn::settingsWriter()
230 while( acquire_sem_etc( settings_thread_sem
, 1, B_RELATIVE_TIMEOUT
, 10000000 ) == B_TIMED_OUT
) {
236 CRadeonAddOn::UnregisterNode( BMediaNode
*node
, BMessage
*settings
)
238 ACQUIRE_BEN( plug_lock
);
240 for( int32 i
= 0; i
< fDevices
.CountItems(); ++i
) {
241 CRadeonPlug
*plug
= (CRadeonPlug
*)fDevices
.ItemAt(i
);
243 if( plug
->getNode() == node
) {
244 // write last settings, so they don't get lost
245 plug
->writeSettings( settings
);
246 plug
->setNode( NULL
);
251 RELEASE_BEN( plug_lock
);
255 CRadeonAddOn::CountFlavors()
257 DPRINT(("CRadeonAddOn::CountFlavors()\n"));
259 if (fInitStatus
< B_OK
)
262 return fDevices
.CountItems();
266 * The pointer to the flavor received only needs to be valid between
267 * successive calls to BCRadeonAddOn::GetFlavorAt().
270 CRadeonAddOn::GetFlavorAt(int32 n
, const flavor_info
**out_info
)
272 DPRINT(("CRadeonAddOn::GetFlavorAt()\n"));
274 if (fInitStatus
< B_OK
)
277 if (n
< 0 || n
>= fDevices
.CountItems() )
280 /* Return the flavor defined in the constructor */
281 *out_info
= ((CRadeonPlug
*)fDevices
.ItemAt(n
))->getFlavorInfo();
286 CRadeonAddOn::InstantiateNodeFor(
287 const flavor_info
*info
, BMessage
*config
, status_t
*out_error
)
289 DPRINT(("CRadeonAddOn::InstantiateNodeFor()\n"));
291 CRadeonProducer
*node
;
293 if (fInitStatus
< B_OK
)
296 if (info
->internal_id
< 0 || info
->internal_id
>= fDevices
.CountItems())
299 CRadeonPlug
*plug
= (CRadeonPlug
*)fDevices
.ItemAt( info
->internal_id
);
301 ACQUIRE_BEN( plug_lock
);
303 if( plug
->getNode() != NULL
) {
308 BMessage single_settings
;
310 // under R5, configuration is always an empty message, so we need to
311 // get our own configuration
312 if( config
== NULL
|| 1 )
313 config
= plug
->getSettings();
315 node
= new CRadeonProducer( this, plug
->getName(),
316 plug
->getDeviceName(), info
->internal_id
, config
);
318 if (node
&& (node
->InitCheck() < B_OK
)) {
319 *out_error
= node
->InitCheck();
325 plug
->setNode( node
);
327 RELEASE_BEN( plug_lock
);
332 status_t
CRadeonAddOn::GetConfigurationFor(
333 BMediaNode
*your_node
,
334 BMessage
*into_message
)
337 CRadeonProducer::configuration_msg msg
;
340 reply_port
= create_port( 1, "GetConfiguration Reply" );
344 msg
.reply_port
= reply_port
;
346 res
= write_port_etc( your_node
->ControlPort(), CRadeonProducer::C_GET_CONFIGURATION
,
347 &msg
, sizeof( msg
), B_TIMEOUT
, 10000000 );
350 CRadeonProducer::configuration_msg_reply
*reply
;
353 reply_size
= port_buffer_size_etc( reply_port
, B_TIMEOUT
, 10000000 );
357 reply
= (CRadeonProducer::configuration_msg_reply
*)malloc( reply_size
);
359 res
= read_port( reply_port
, &code
, reply
, reply_size
);
360 if( res
== reply_size
) {
361 if( code
!= CRadeonProducer::C_GET_CONFIGURATION_REPLY
)
367 res
= into_message
->Unflatten( &reply
->config
);
375 delete_port( reply_port
);
381 CRadeonAddOn::RecursiveScan(const char* rootPath
, BEntry
*rootEntry
= NULL
)
385 if( rootEntry
!= NULL
)
386 root
.SetTo( rootEntry
);
387 else if( rootPath
!= NULL
) {
388 root
.SetTo( rootPath
);
390 PRINT(("Error in MultiAudioAddOn::RecursiveScan null params\n"));
397 while( root
.GetNextEntry( &entry
) > B_ERROR
) {
398 if(entry
.IsDirectory()) {
399 RecursiveScan( rootPath
, &entry
);
404 entry
.GetPath(&path
);
406 CRadeon
device( path
.Path() );
408 if( device
.InitCheck() != B_OK
)
411 CVIPPort
vip_port( device
);
413 // if there is a Rage Theatre, then there should be Video-In
414 if( vip_port
.InitCheck() == B_OK
&&
415 ((vip_port
.FindVIPDevice( C_THEATER100_VIP_DEVICE_ID
) >= 0)
416 || (vip_port
.FindVIPDevice( C_THEATER200_VIP_DEVICE_ID
) >= 0)))
418 fDevices
.AddItem( new CRadeonPlug( this, path
, cur_id
++ ));
428 make_media_addon(image_id imid
)
430 return new CRadeonAddOn(imid
);