1 /******************************************************************************
2 /
3 / File: RadeonProducer.cpp
4 /
5 / Description: ATI Radeon Video Producer media node.
6 /
7 / Copyright 2001, Carlos Hasan
8 /
9 *******************************************************************************/
10
11 #include <fcntl.h>
12 #include <malloc.h>
13 #include <math.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <sys/uio.h>
17 #include <unistd.h>
18 #include <scheduler.h>
19
20 #include <media/Buffer.h>
21 #include <media/BufferGroup.h>
22 #include <media/ParameterWeb.h>
23 #include <media/TimeSource.h>
24
25 #include <support/Autolock.h>
26 #include <support/Debug.h>
27
28 #include <app/Message.h>
29
30 #include "RadeonAddOn.h"
31 #include "VideoIn.h"
32
33 #define DPRINT(args) { PRINT(("\x1b[0;30;35m")); PRINT(args); PRINT(("\x1b[0;30;47m")); }
34
35 #define TOUCH(x) ((void)(x))
36
37 #define PRINTF(a,b) \
38 do { \
39 if (a < 2) { \
40 printf("CRadeonProducer::"); \
41 printf b; \
42 } \
43 } while (0)
44
45 #include "RadeonProducer.h"
46
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
BeToVideoInStandard(int32 be_standard)52 video_in_standard BeToVideoInStandard( int32 be_standard )
53 {
54
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;
67 }
68 }
69
VideoInStandardToBe(video_in_standard standard)70 int32 VideoInStandardToBe( video_in_standard standard )
71 {
72 DPRINT(("VideoInStandardToBe %d \n", standard));
73 switch( 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;
83 default: return 1;
84 }
85 }
86
FindInt32(BMessage * config,EOptions option,int32 min_value,int32 max_value,int32 default_value,int32 * value)87 status_t CRadeonProducer::FindInt32(
88 BMessage *config, EOptions option, int32 min_value, int32 max_value,
89 int32 default_value, int32 *value )
90 {
91 char name[5];
92 status_t res;
93
94 *value = default_value;
95
96 *(int32 *)name = option;
97 name[4] = 0;
98
99 res = config->FindInt32( name, value );
100 if( res == B_NAME_NOT_FOUND )
101 return B_OK;
102
103 if( res != B_OK )
104 return res;
105
106 *value = MAX( *value, min_value );
107 *value = MIN( *value, max_value );
108 return B_OK;
109 }
110
CRadeonProducer(CRadeonAddOn * addon,const char * name,const char * device_name,int32 internal_id,BMessage * config)111 CRadeonProducer::CRadeonProducer(
112 CRadeonAddOn *addon, const char *name, const char *device_name, int32 internal_id,
113 BMessage *config )
114 : BMediaNode(name),
115 BMediaEventLooper(),
116 BBufferProducer(B_MEDIA_RAW_VIDEO),
117 BControllable(),
118 fVideoIn( device_name )
119 {
120 DPRINT(("CRadeonProducer::CRadeonProducer()\n"));
121
122 fInitStatus = B_NO_INIT;
123
124 fInternalID = internal_id;
125 fAddOn = addon;
126
127 fBufferGroup = NULL;
128 //fUsedBufferGroup = NULL;
129
130 fProcessingLatency = 0LL;
131
132 //fConnected = false;
133 fEnabled = true;
134
135 AddNodeKind(B_PHYSICAL_INPUT);
136
137 if( fVideoIn.InitCheck() == B_OK )
138 fInitStatus = B_OK;
139
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;
143 fFormat = B_RGB32;
144 fResolution = 4;
145 fTuner = 25;
146 fBrightness = 0;
147 fContrast = 0;
148 fSaturation = 0;
149 fHue = 0;
150 fSharpness = 0;
151
152 if( config != NULL ) {
153 status_t res;
154 int32 standard;
155
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 )
179 {
180 DPRINT(("Corrupted settings (%s)\n", strerror( res )));
181 }
182
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 );
187
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;
191
192 // format ids are scattered, so we must verify them manually
193 switch( fFormat ) {
194 case B_YCbCr422:
195 case B_GRAY8:
196 case B_RGB15:
197 case B_RGB16:
198 case B_RGB32:
199 break;
200 default:
201 fFormat = B_RGB16;
202 }
203 }
204
205 fSourceLastChange =
206 fStandardLastChange =
207 fModeLastChange =
208 fFormatLastChange =
209 fResolutionLastChange =
210 fTunerLastChange =
211 fBrightnessLastChange =
212 fContrastLastChange =
213 fSaturationLastChange =
214 fHueLastChange =
215 fSharpnessLastChange = system_time();
216
217 fOutput.destination = media_destination::null;
218 strcpy(fOutput.name, Name());
219
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;
223 }
224
225
setupWeb()226 void CRadeonProducer::setupWeb()
227 {
228 ///////////
229 /* Set up the parameter web */
230
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");*/
237
238 BParameterGroup *controls1 = controls->MakeGroup("Controls1");
239 BParameterGroup *controls2 = controls->MakeGroup("Controls2");
240 BParameterGroup *controls3 = controls->MakeGroup("Controls3");
241
242 BParameterGroup *options1 = options->MakeGroup("Options1");
243 BParameterGroup *options2 = options->MakeGroup("Options2");
244
245 /*BParameterGroup *audio1 = audio->MakeGroup("Audio1");
246 BParameterGroup *audio2 = audio->MakeGroup("Audio2");*/
247
248
249 // Controls
250 if ((fVideoIn.Capabilities() & C_VIDEO_IN_HAS_TUNER) != 0) {
251 // Controls.Channel
252 BDiscreteParameter *tuner = controls1->MakeDiscreteParameter(
253 P_TUNER, B_MEDIA_NO_TYPE, "Channel:", B_TUNER_CHANNEL);
254
255 for (int channel = 0; channel <= 125; channel++) {
256 char buffer[32];
257 sprintf(buffer, "%d", channel);
258 tuner->AddItem(channel, buffer);
259 }
260 }
261
262 // Controls.Source
263 BDiscreteParameter *source = controls1->MakeDiscreteParameter(
264 P_SOURCE, B_MEDIA_RAW_VIDEO, "Video Input:", "Video Input:");
265
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");
272
273 // TODO:
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");
282 */
283
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);
288
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);
291
292
293 // Options.Resolution
294 BDiscreteParameter *resolution = options1->MakeDiscreteParameter(
295 P_RESOLUTION, B_MEDIA_RAW_VIDEO, "Default Image Size:", B_RESOLUTION);
296
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");
304
305 // Options.Format
306 BDiscreteParameter *format = options1->MakeDiscreteParameter(
307 P_FORMAT, B_MEDIA_RAW_VIDEO, "Default Colors:", B_COLOR_SPACE);
308
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");
314
315 // Options.Standard
316 BDiscreteParameter *standard = options2->MakeDiscreteParameter(
317 P_STANDARD, B_MEDIA_RAW_VIDEO, "Video Format:", B_VIDEO_FORMAT);
318
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");
328
329 // Options.Mode
330 BDiscreteParameter *mode = options2->MakeDiscreteParameter(
331 P_MODE, B_MEDIA_RAW_VIDEO, "Video Interlace:", B_GENERIC);
332
333 mode->AddItem(C_VIDEO_IN_FIELD, "Field");
334 mode->AddItem(C_VIDEO_IN_BOB, "Bob");
335 mode->AddItem(C_VIDEO_IN_WEAVE, "Weave");
336
337
338 // TODO:
339 /*
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");
345
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");
353
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");*/
360
361 /* After this call, the BControllable owns the BParameterWeb object and
362 * will delete it for you */
363 SetParameterWeb(web);
364 /////////
365 }
366
~CRadeonProducer()367 CRadeonProducer::~CRadeonProducer()
368 {
369 DPRINT(("CRadeonProducer::~CRadeonProducer()\n"));
370
371 if (fInitStatus == B_OK) {
372 /* Clean up after ourselves, in case the application didn't make us
373 * do so. */
374 /*if (fConnected)
375 Disconnect(fOutput.source, fOutput.destination);*/
376
377 HandleStop();
378 }
379
380 delete fBufferGroup;
381 fBufferGroup = NULL;
382
383 BMessage settings;
384
385 GetConfiguration( &settings );
386
387 fAddOn->UnregisterNode( this, &settings );
388
389 Quit();
390 }
391
392 /* BMediaNode */
393
394 port_id
ControlPort() const395 CRadeonProducer::ControlPort() const
396 {
397 return BMediaNode::ControlPort();
398 }
399
400 BMediaAddOn *
AddOn(int32 * internal_id) const401 CRadeonProducer::AddOn(int32 *internal_id) const
402 {
403 if (internal_id)
404 *internal_id = fInternalID;
405 return fAddOn;
406 }
407
408 status_t
HandleMessage(int32 message,const void * data,size_t size)409 CRadeonProducer::HandleMessage(int32 message, const void *data, size_t size)
410 {
411 //DPRINT(("CRadeonProducer::HandleMessage()\n"));
412
413 switch( message ) {
414 case C_GET_CONFIGURATION: {
415 const configuration_msg *request = (const configuration_msg *)data;
416 BMessage msg;
417 configuration_msg_reply *reply;
418 size_t reply_size, config_size;
419 status_t res;
420
421 if( size < sizeof( configuration_msg ))
422 return B_ERROR;
423
424 res = GetConfiguration( &msg );
425
426 config_size = msg.FlattenedSize();
427 reply_size = sizeof( *reply ) + config_size;
428 reply = (configuration_msg_reply *)malloc( reply_size );
429 if( reply == NULL )
430 return B_NO_MEMORY;
431
432 reply->res = res;
433 reply->config_size = config_size;
434 msg.Flatten( &reply->config, config_size );
435
436 write_port_etc( request->reply_port, C_GET_CONFIGURATION_REPLY,
437 reply, reply_size, B_TIMEOUT, 0 );
438
439 free( reply );
440 return B_OK;
441 }
442 default:
443 return B_ERROR;
444 // return BControllable::HandleMessage(message, data, size);
445 }
446 }
447
448 void
Preroll()449 CRadeonProducer::Preroll()
450 {
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"));
454 }
455
456 void
SetTimeSource(BTimeSource * time_source)457 CRadeonProducer::SetTimeSource(BTimeSource *time_source)
458 {
459 DPRINT(("CRadeonProducer::SetTimeSource()\n"));
460
461 /* Tell frame generation thread to recalculate delay value */
462 //release_sem(fFrameSync);
463 }
464
465 status_t
RequestCompleted(const media_request_info & info)466 CRadeonProducer::RequestCompleted(const media_request_info &info)
467 {
468 DPRINT(("CRadeonProducer::RequestCompleted()\n"));
469
470 return BMediaNode::RequestCompleted(info);
471 }
472
473 /* BMediaEventLooper */
474
475 void
NodeRegistered()476 CRadeonProducer::NodeRegistered()
477 {
478 DPRINT(("CRadeonProducer::NodeRegistered()\n"));
479
480 if (fInitStatus != B_OK) {
481 ReportError(B_NODE_IN_DISTRESS);
482 return;
483 }
484
485 setupWeb();
486 //!!//
487
488 fOutput.node = Node();
489 fOutput.source.port = ControlPort();
490 fOutput.source.id = 0;
491
492 /* Tailor these for the output of your device */
493 /********
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;
498 ********/
499
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 ));
504
505 /* Start the BMediaEventLooper control loop running */
506 Run();
507 }
508
509 void
Start(bigtime_t performance_time)510 CRadeonProducer::Start(bigtime_t performance_time)
511 {
512 DPRINT(("CRadeonProducer::Start()\n"));
513
514 BMediaEventLooper::Start(performance_time);
515 }
516
517 void
Stop(bigtime_t performance_time,bool immediate)518 CRadeonProducer::Stop(bigtime_t performance_time, bool immediate)
519 {
520 DPRINT(("CRadeonProducer::Stop()\n"));
521
522 BMediaEventLooper::Stop(performance_time, immediate);
523 }
524
525 void
Seek(bigtime_t media_time,bigtime_t performance_time)526 CRadeonProducer::Seek(bigtime_t media_time, bigtime_t performance_time)
527 {
528 DPRINT(("CRadeonProducer::Seek()\n"));
529
530 BMediaEventLooper::Seek(media_time, performance_time);
531 }
532
533 void
TimeWarp(bigtime_t at_real_time,bigtime_t to_performance_time)534 CRadeonProducer::TimeWarp(bigtime_t at_real_time, bigtime_t to_performance_time)
535 {
536 DPRINT(("CRadeonProducer::TimeWarp()\n"));
537
538 BMediaEventLooper::TimeWarp(at_real_time, to_performance_time);
539 }
540
541 status_t
AddTimer(bigtime_t at_performance_time,int32 cookie)542 CRadeonProducer::AddTimer(bigtime_t at_performance_time, int32 cookie)
543 {
544 DPRINT(("CRadeonProducer::AddTimer()\n"));
545
546 return BMediaEventLooper::AddTimer(at_performance_time, cookie);
547 }
548
549 void
SetRunMode(run_mode mode)550 CRadeonProducer::SetRunMode(run_mode mode)
551 {
552 DPRINT(("CRadeonProducer::SetRunMode()\n"));
553
554 BMediaEventLooper::SetRunMode(mode);
555 }
556
557 void
HandleEvent(const media_timed_event * event,bigtime_t lateness,bool realTimeEvent)558 CRadeonProducer::HandleEvent(const media_timed_event *event,
559 bigtime_t lateness, bool realTimeEvent)
560 {
561 //DPRINT(("CRadeonProducer::HandleEvent()\n"));
562
563 TOUCH(lateness); TOUCH(realTimeEvent);
564
565 switch(event->type)
566 {
567 case BTimedEventQueue::B_START:
568 HandleStart(event->event_time);
569 break;
570 case BTimedEventQueue::B_STOP:
571 HandleStop();
572 break;
573 case BTimedEventQueue::B_WARP:
574 HandleTimeWarp(event->bigdata);
575 break;
576 case BTimedEventQueue::B_SEEK:
577 HandleSeek(event->bigdata);
578 break;
579 case BTimedEventQueue::B_HANDLE_BUFFER:
580 case BTimedEventQueue::B_DATA_STATUS:
581 case BTimedEventQueue::B_PARAMETER:
582 default:
583 PRINTF(-1, ("HandleEvent: Unhandled event -- %lx\n", event->type));
584 break;
585 case BTimedEventQueue::B_HARDWARE:
586 HandleHardware();
587 break;
588 }
589
590 //DPRINT(("CRadeonProducer::HandleEvent() done\n"));
591 }
592
593 void
CleanUpEvent(const media_timed_event * event)594 CRadeonProducer::CleanUpEvent(const media_timed_event *event)
595 {
596 DPRINT(("CRadeonProducer::CleanUpEvent()\n"));
597
598 BMediaEventLooper::CleanUpEvent(event);
599 }
600
601 bigtime_t
OfflineTime()602 CRadeonProducer::OfflineTime()
603 {
604 return BMediaEventLooper::OfflineTime();
605 }
606
607 void
ControlLoop()608 CRadeonProducer::ControlLoop()
609 {
610 BMediaEventLooper::ControlLoop();
611 }
612
613 status_t
DeleteHook(BMediaNode * node)614 CRadeonProducer::DeleteHook(BMediaNode * node)
615 {
616 DPRINT(("CRadeonProducer::DeleteHook()\n"));
617
618 return BMediaEventLooper::DeleteHook(node);
619 }
620
621
622
623 /* BBufferProducer */
624
625 // choose capture mode according to format and update format according to that
626 status_t
verifySetMode(media_format * format)627 CRadeonProducer::verifySetMode( media_format *format )
628 {
629 float frame_rate = fVideoIn.getFrameRate(
630 BeToVideoInStandard( fStandard )) / 1000.0f;
631
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;
636 } else {
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;
641 else {
642 DPRINT(( "Unsupported field rate for active TV standard (%f)\n",
643 format->u.raw_video.field_rate ));
644 return B_MEDIA_BAD_FORMAT;
645 }
646 }
647
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;
651 else {
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;
658 }
659 }
660
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;
664 else {
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;
669 }
670 }
671
672 } else {
673 DPRINT(( "Invalid interlace mode (%d)\n", format->u.raw_video.interlace ));
674 return B_MEDIA_BAD_FORMAT;
675 }
676
677 return B_OK;
678 }
679
680 /*
681 Map BeOS capture mode to internal capture mode.
682 */
683 int32
extractCaptureMode(const media_format * format)684 CRadeonProducer::extractCaptureMode( const media_format *format )
685 {
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;
695 else
696 return fMode;
697 }
698
699 // check pixel aspect of format and set it if it's wildcarded
700 status_t
verifySetPixelAspect(media_format * format)701 CRadeonProducer::verifySetPixelAspect( media_format *format )
702 {
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 )
706 {
707 if( format->u.raw_video.pixel_width_aspect !=
708 format->u.raw_video.pixel_height_aspect )
709 {
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;
714 }
715 } else {
716 format->u.raw_video.pixel_width_aspect = 1;
717 format->u.raw_video.pixel_height_aspect = 1;
718 }
719
720 return B_OK;
721
722 #if 0
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 )
728 {
729 double ratio = mode == C_VIDEO_IN_WEAVE ? 1 : 0.5;
730
731 if( (float)format->u.raw_video.pixel_width_aspect /
732 format->u.raw_video.pixel_height_aspect != ratio )
733 {
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;
738 }
739 } else {
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;
743 }
744
745 return B_OK;
746 #endif
747 }
748
749 // verify active range defined as format
750 status_t
verifyActiveRange(media_format * format)751 CRadeonProducer::verifyActiveRange( media_format *format )
752 {
753 CRadeonRect active_rect;
754
755 fVideoIn.getActiveRange( BeToVideoInStandard( fStandard ), active_rect );
756
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;
761 }
762 }
763
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;
771 }
772 }
773
774 return B_OK;
775 }
776
777
778 // set active range in format if yet undefined
779 void
setActiveRange(media_format * format)780 CRadeonProducer::setActiveRange( media_format *format )
781 {
782 CRadeonRect active_rect;
783
784 fVideoIn.getActiveRange( BeToVideoInStandard( fStandard ), active_rect );
785
786 if( format->u.raw_video.first_active == media_raw_video_format::wildcard.first_active )
787 format->u.raw_video.first_active = 0;
788
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;
791 }
792
793
794 // verify requested orientation
795 status_t
verifyOrientation(media_format * format)796 CRadeonProducer::verifyOrientation( media_format *format )
797 {
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;
802 }
803 }
804
805 return B_OK;
806 }
807
808
809 // set image orientation if yet undefined
810 void
setOrientation(media_format * format)811 CRadeonProducer::setOrientation( media_format *format )
812 {
813 if( format->u.raw_video.orientation == media_raw_video_format::wildcard.orientation )
814 format->u.raw_video.orientation = B_VIDEO_TOP_LEFT_RIGHT;
815 }
816
817
818 // verify requested pixel format
819 status_t
verifyPixelFormat(media_format * format)820 CRadeonProducer::verifyPixelFormat( media_format *format )
821 {
822 if( format->u.raw_video.display.format !=
823 media_raw_video_format::wildcard.display.format )
824 {
825 switch( format->u.raw_video.display.format ) {
826 case B_RGB32:
827 case B_RGB16:
828 case B_RGB15:
829 case B_YCbCr422:
830 case B_GRAY8:
831 break;
832
833 default:
834 DPRINT(("Unsupported colour space (%x)\n",
835 format->u.raw_video.display.format ));
836 return B_MEDIA_BAD_FORMAT;
837 }
838 }
839
840 return B_OK;
841 }
842
843
844 // set pixel format to user-defined default if not set yet
845 void
setPixelFormat(media_format * format)846 CRadeonProducer::setPixelFormat( media_format *format )
847 {
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;
851 }
852
853 /*
854 Verify video size and set it if undefined.
855 */
856 status_t
verifySetSize(media_format * format,int32 mode,bool set_bytes_per_row)857 CRadeonProducer::verifySetSize(
858 media_format *format, int32 mode, bool set_bytes_per_row )
859 {
860 CRadeonRect active_rect;
861
862 fVideoIn.getActiveRange( BeToVideoInStandard( fStandard ), active_rect );
863
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
866 // set both
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 )
871 {
872 uint32 max_height = active_rect.Height();
873
874 if( mode != C_VIDEO_IN_WEAVE )
875 max_height /= 2;
876
877 if( format->u.raw_video.display.line_width > (uint32)active_rect.Width() ||
878 format->u.raw_video.display.line_count > max_height )
879 {
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;
884 }
885
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
889
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;
894 }
895
896 } else {
897 switch (fResolution) {
898 case 0:
899 format->u.raw_video.display.line_width = 640;
900 format->u.raw_video.display.line_count = 480;
901 break;
902 case 3:
903 format->u.raw_video.display.line_width = 480;
904 format->u.raw_video.display.line_count = 360;
905 break;
906 case 4:
907 format->u.raw_video.display.line_width = 720;
908 format->u.raw_video.display.line_count = 480;
909 break;
910 case 5:
911 format->u.raw_video.display.line_width = 720;
912 format->u.raw_video.display.line_count = 576;
913 break;
914 case 6:
915 format->u.raw_video.display.line_width = 768;
916 format->u.raw_video.display.line_count = 576;
917 break;
918 case 1:
919 format->u.raw_video.display.line_width = 320;
920 format->u.raw_video.display.line_count = 240;
921 break;
922 case 2:
923 format->u.raw_video.display.line_width = 160;
924 format->u.raw_video.display.line_count = 120;
925 break;
926 }
927
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;
930
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();
933
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;
938 }
939 }
940
941 if( format->u.raw_video.display.format != media_raw_video_format::wildcard.display.format ) {
942 uint32 bytes_per_row;
943
944 switch( format->u.raw_video.display.format ) {
945 case B_RGB32:
946 bytes_per_row =
947 format->u.raw_video.display.line_width * 4;
948 break;
949
950 case B_RGB15:
951 case B_RGB16:
952 case B_YCbCr422:
953 bytes_per_row =
954 format->u.raw_video.display.line_width * 2;
955 break;
956
957 default:
958 bytes_per_row =
959 format->u.raw_video.display.line_width;
960 }
961
962 if( format->u.raw_video.display.bytes_per_row !=
963 media_raw_video_format::wildcard.display.bytes_per_row )
964 {
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;
969 }
970 } else if( set_bytes_per_row )
971 format->u.raw_video.display.bytes_per_row = bytes_per_row;
972 }
973
974
975 return B_OK;
976 }
977
978
979 // verify "offset" parameters of format
980 status_t
verifyFormatOffsets(media_format * format)981 CRadeonProducer::verifyFormatOffsets( media_format *format )
982 {
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 )
986 {
987 DPRINT(( "Requested pixel offset is not zero" ));
988 return B_MEDIA_BAD_FORMAT;
989 }
990
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 )
994 {
995 DPRINT(( "Requested line offset is not zero" ));
996 return B_MEDIA_BAD_FORMAT;
997 }
998
999 return B_OK;
1000 }
1001
1002
1003 // set "offset" parameters of format if not set yet
1004 void
setFormatOffsets(media_format * format)1005 CRadeonProducer::setFormatOffsets( media_format *format )
1006 {
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;
1010
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;
1014 }
1015
1016
1017 // verify "flags" parameter of format
1018 status_t
verifyFormatFlags(media_format * format)1019 CRadeonProducer::verifyFormatFlags( media_format *format )
1020 {
1021 if( format->u.raw_video.display.flags !=
1022 media_raw_video_format::wildcard.display.flags &&
1023 format->u.raw_video.display.flags != 0 )
1024 {
1025 DPRINT(( "Requested display flags are not zero" ));
1026 return B_MEDIA_BAD_FORMAT;
1027 }
1028
1029 return B_OK;
1030 }
1031
1032
1033 // set "flags" parameter of format if not set yet
1034 void
setFormatFlags(media_format * format)1035 CRadeonProducer::setFormatFlags( media_format *format )
1036 {
1037 if( format->u.raw_video.display.flags ==
1038 media_raw_video_format::wildcard.display.flags )
1039 format->u.raw_video.display.flags = 0;
1040 }
1041
1042
1043 /*
1044 * Fill out all wildcards in a format descriptor.
1045 */
1046 status_t
finalizeFormat(media_format * format)1047 CRadeonProducer::finalizeFormat( media_format *format )
1048 {
1049 if (format->type != B_MEDIA_RAW_VIDEO)
1050 return B_MEDIA_BAD_FORMAT;
1051
1052 status_t res;
1053
1054 res = verifySetMode( format );
1055 if( res != B_OK )
1056 return res;
1057
1058 int32 mode = extractCaptureMode( format );
1059
1060 res = verifyActiveRange( format );
1061 if( res != B_OK )
1062 return res;
1063
1064 setActiveRange( format );
1065
1066 res = verifyOrientation( format );
1067 if( res != B_OK )
1068 return res;
1069
1070 res = verifySetPixelAspect( format );
1071 if( res != B_OK )
1072 return res;
1073
1074 res = verifyPixelFormat( format );
1075 if( res != B_OK )
1076 return res;
1077
1078 setPixelFormat( format);
1079
1080 res = verifySetSize( format, mode, true );
1081 if( res != B_OK )
1082 return res;
1083
1084 res = verifyFormatOffsets( format );
1085 if( res != B_OK )
1086 return res;
1087
1088 setFormatOffsets( format );
1089
1090 res = verifyFormatFlags( format );
1091 if( res != B_OK )
1092 return res;
1093
1094 setFormatFlags( format );
1095 return res;
1096 }
1097
1098
1099 /*
1100 * Someone has no idea what format we usually provide and asks us.
1101 *
1102 * It's not really clear whether we are allowed to return wildcards.
1103 */
1104 status_t
FormatSuggestionRequested(media_type type,int32 quality,media_format * format)1105 CRadeonProducer::FormatSuggestionRequested(
1106 media_type type, int32 quality, media_format *format)
1107 {
1108 DPRINT(("CRadeonProducer::FormatSuggestionRequested()\n"));
1109
1110 if (type != B_MEDIA_RAW_VIDEO)
1111 return B_MEDIA_BAD_FORMAT;
1112
1113 TOUCH(quality);
1114
1115 format->type = B_MEDIA_RAW_VIDEO;
1116
1117 format->u.raw_video = media_raw_video_format::wildcard;
1118
1119 finalizeFormat( format );
1120
1121 return B_OK;
1122 }
1123
1124
1125 /*
1126 Initial format proposal as part of a connection establishment.
1127
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 .
1132 */
1133 status_t
FormatProposal(const media_source & output,media_format * format)1134 CRadeonProducer::FormatProposal(const media_source &output, media_format *format)
1135 {
1136 char buffer[256];
1137
1138 DPRINT(("CRadeonProducer::FormatProposal()\n"));
1139
1140 if( format == NULL )
1141 return B_BAD_VALUE;
1142
1143 if( output != fOutput.source )
1144 return B_MEDIA_BAD_SOURCE;
1145
1146 string_for_format(*format, buffer, sizeof(buffer));
1147
1148 DPRINT(("CRadeonProducer::FormatProposal() - in=%s\n", buffer));
1149
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;
1154 }
1155
1156 if (format->type != B_MEDIA_RAW_VIDEO)
1157 return B_MEDIA_BAD_FORMAT;
1158
1159 status_t res;
1160
1161 // first, choose capture mode, so we know the maximum video size
1162 res = verifySetMode( format );
1163 if( res != B_OK )
1164 return res;
1165
1166 int32 mode = extractCaptureMode( format );
1167
1168 res = verifyActiveRange( format );
1169 if( res != B_OK )
1170 return res;
1171
1172 res = verifyOrientation( format );
1173 if( res != B_OK )
1174 return res;
1175
1176 setOrientation( format );
1177
1178 // simple aspect calculation: we always use 1:1, so setting this is easy
1179 res = verifySetPixelAspect( format );
1180 if( res != B_OK )
1181 return res;
1182
1183 res = verifyPixelFormat( format );
1184 if( res != B_OK )
1185 return res;
1186
1187 // if we don't set it, the consumer usually chooses a stupid format
1188 setPixelFormat( format );
1189
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 );
1196 if( res != B_OK )
1197 return res;
1198
1199 res = verifyFormatOffsets( format );
1200 if( res != B_OK )
1201 return res;
1202
1203 res = verifyFormatFlags( format );
1204 if( res != B_OK )
1205 return res;
1206
1207 string_for_format(*format, buffer, sizeof(buffer));
1208
1209 DPRINT(("CRadeonProducer::FormatProposal() - out=%s\n", buffer));
1210
1211 return B_OK;
1212 }
1213
1214 status_t
FormatChangeRequested(const media_source & source,const media_destination & destination,media_format * io_format,int32 * _deprecated_)1215 CRadeonProducer::FormatChangeRequested(const media_source &source,
1216 const media_destination &destination, media_format *io_format,
1217 int32 *_deprecated_)
1218 {
1219 DPRINT(("CRadeonProducer::FormatChangeRequested()\n"));
1220
1221 TOUCH(destination); TOUCH(io_format); TOUCH(_deprecated_);
1222 if (source != fOutput.source)
1223 return B_MEDIA_BAD_SOURCE;
1224
1225 return B_ERROR;
1226 }
1227
1228 status_t
GetNextOutput(int32 * cookie,media_output * out_output)1229 CRadeonProducer::GetNextOutput(int32 *cookie, media_output *out_output)
1230 {
1231 DPRINT(("CRadeonProducer::GetNextOutput()\n"));
1232
1233 if (!out_output)
1234 return B_BAD_VALUE;
1235
1236 if ((*cookie) != 0)
1237 return B_BAD_INDEX;
1238
1239 *out_output = fOutput;
1240 (*cookie)++;
1241 return B_OK;
1242 }
1243
1244 status_t
DisposeOutputCookie(int32 cookie)1245 CRadeonProducer::DisposeOutputCookie(int32 cookie)
1246 {
1247 DPRINT(("CRadeonProducer::DisposeOutputCookie()\n"));
1248
1249 TOUCH(cookie);
1250
1251 return B_OK;
1252 }
1253
1254 status_t
SetBufferGroup(const media_source & for_source,BBufferGroup * group)1255 CRadeonProducer::SetBufferGroup(const media_source &for_source,
1256 BBufferGroup *group)
1257 {
1258 DPRINT(("CRadeonProducer::SetBufferGroup()\n"));
1259
1260 if( for_source != fOutput.source )
1261 return B_MEDIA_BAD_SOURCE;
1262
1263 if( group != NULL ) {
1264 delete fBufferGroup;
1265 fBufferGroup = group;
1266 }
1267
1268 return B_OK;
1269 }
1270
1271 status_t
VideoClippingChanged(const media_source & for_source,int16 num_shorts,int16 * clip_data,const media_video_display_info & display,int32 * _deprecated_)1272 CRadeonProducer::VideoClippingChanged(const media_source &for_source,
1273 int16 num_shorts, int16 *clip_data,
1274 const media_video_display_info &display, int32 *_deprecated_)
1275 {
1276 DPRINT(("CRadeonProducer::VideoClippingChanged()\n"));
1277
1278 TOUCH(for_source); TOUCH(num_shorts); TOUCH(clip_data);
1279 TOUCH(display); TOUCH(_deprecated_);
1280
1281 return B_ERROR;
1282 }
1283
1284 status_t
GetLatency(bigtime_t * out_latency)1285 CRadeonProducer::GetLatency(bigtime_t *out_latency)
1286 {
1287 DPRINT(("CRadeonProducer::GetLatency()\n"));
1288
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);
1294
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;
1300
1301 bigtime_t buffer_latency = fProcessingLatency;
1302 BBufferProducer::GetLatency( &buffer_latency );
1303
1304 *out_latency = SchedulingLatency() + capture_latency + fProcessingLatency +
1305 buffer_latency;
1306
1307 DPRINT(("latency=%lld\n", *out_latency));
1308
1309 return B_OK;
1310 }
1311
1312
1313 status_t
PrepareToConnect(const media_source & source,const media_destination & destination,media_format * format,media_source * out_source,char * out_name)1314 CRadeonProducer::PrepareToConnect(const media_source &source,
1315 const media_destination &destination, media_format *format,
1316 media_source *out_source, char *out_name)
1317 {
1318 DPRINT(("CRadeonProducer::PrepareToConnect()\n"));
1319
1320 PRINTF(1, ("PrepareToConnect() %ldx%ld\n", \
1321 format->u.raw_video.display.line_width, \
1322 format->u.raw_video.display.line_count));
1323
1324 if (source != fOutput.source) {
1325 DPRINT(("bad source\n"));
1326 return B_MEDIA_BAD_SOURCE;
1327 }
1328
1329 if (fOutput.destination != media_destination::null) {
1330 DPRINT(("already connected\n"));
1331 return B_MEDIA_ALREADY_CONNECTED;
1332 }
1333
1334 char buffer[256];
1335 string_for_format(*format, buffer, sizeof(buffer));
1336 DPRINT(("CRadeonProducer::PrepareToConnect() - in=%s\n", buffer));
1337
1338 status_t res = finalizeFormat( format );
1339 if( res != B_OK )
1340 return res;
1341
1342 *out_source = fOutput.source;
1343 strcpy(out_name, fOutput.name);
1344
1345 string_for_format(*format, buffer, sizeof(buffer));
1346 DPRINT(("CRadeonProducer::PrepareToConnect() - out=%s\n", buffer));
1347
1348 // reserve connection
1349 fOutput.destination = destination;
1350
1351 DPRINT(("finished\n"));
1352
1353 return B_OK;
1354 }
1355
1356 void
setDefaultBufferGroup()1357 CRadeonProducer::setDefaultBufferGroup()
1358 {
1359 DPRINT(("CRadeonProducer::setDefaultBufferGroup()\n"));
1360 /*delete fBufferGroup;
1361 fBufferGroup = NULL;*/
1362 if( fBufferGroup != NULL ) {
1363 DPRINT(("Buffer already set\n"));
1364 return;
1365 }
1366
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 );
1371
1372 if (fBufferGroup->InitCheck() < B_OK) {
1373 delete fBufferGroup;
1374 fBufferGroup = NULL;
1375 return;
1376 }
1377 }
1378
1379 void
startCapturing()1380 CRadeonProducer::startCapturing()
1381 {
1382 if( RunState() != BMediaEventLooper::B_STARTED ||
1383 fOutput.destination == media_destination::null )
1384 return;
1385
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);
1392
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);
1397
1398 char *tmp_buffer;
1399 tmp_buffer = (char *)malloc(
1400 fOutput.format.u.raw_video.display.bytes_per_row *
1401 fOutput.format.u.raw_video.display.line_count );
1402
1403 int field_sequence;
1404 short field_number;
1405 bigtime_t capture_time;
1406
1407 // do a real capturing to prime everything
1408 fVideoIn.Capture(
1409 tmp_buffer != NULL ? fOutput.format.u.raw_video.display.format : B_NO_COLOR_SPACE,
1410 tmp_buffer,
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 );
1414
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 ) {
1418 fVideoIn.Capture(
1419 B_NO_COLOR_SPACE,
1420 NULL,
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 );
1424
1425 DPRINT(("Captured: %lld, current: %lld\n", capture_time, system_time() ));
1426 }
1427
1428 // do a real capturing to see how long it takes until the
1429 // buffer is ready, i.e. including DMA and colour conversion
1430 fVideoIn.Capture(
1431 tmp_buffer != NULL ? fOutput.format.u.raw_video.display.format : B_NO_COLOR_SPACE,
1432 tmp_buffer,
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 );
1436
1437 DPRINT(("Captured: %lld, current: %lld\n", capture_time, system_time() ));
1438
1439 // now we know our internal latency
1440 fProcessingLatency = system_time() - capture_time;
1441
1442 DPRINT(("Processing latency: %dµs\n", fProcessingLatency ));
1443
1444 // store field sequence to start with zero
1445 // (capture-internal field sequence always counts up)
1446 fFieldSequenceBase = field_sequence;
1447
1448 if( tmp_buffer != NULL )
1449 free(tmp_buffer);
1450
1451 // tell latence MediaEventLooper so it can schedule events properly ahead
1452 bigtime_t total_latency;
1453
1454 GetLatency( &total_latency );
1455 SetEventLatency( total_latency );
1456
1457 // Create the buffer group
1458 setDefaultBufferGroup();
1459
1460 //fUsedBufferGroup = fBufferGroup;
1461
1462 // schedule a capture event after one field's time
1463 RealTimeQueue()->FlushEvents( 0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HARDWARE );
1464
1465 media_timed_event event(
1466 capture_time + 1000000 / fOutput.format.u.raw_video.field_rate,
1467 BTimedEventQueue::B_HARDWARE);
1468
1469 RealTimeQueue()->AddEvent(event);
1470 }
1471
1472 void
Connect(status_t error,const media_source & source,const media_destination & destination,const media_format & format,char * io_name)1473 CRadeonProducer::Connect(status_t error, const media_source &source,
1474 const media_destination &destination, const media_format &format,
1475 char *io_name)
1476 {
1477 // we even get called if consumer reported error in AcceptFormat;
1478 // in this case, we must release the source already reserved by
1479 // PrepareToConnect
1480 if( error != B_OK ) {
1481 DPRINT(( "Connect: Consumer returned error (%s) - releasing source",
1482 strerror( error )));
1483 fOutput.destination = media_destination::null;
1484 return;
1485 }
1486
1487 if( source != fOutput.source ) {
1488 DPRINT(( "Connect: Wrong source specified\n"));
1489 return;
1490 }
1491
1492 fOutput.destination = destination;
1493 fOutput.format = format;
1494 fCurMode = extractCaptureMode( &format );
1495
1496 char buffer[256];
1497 string_for_format(format, buffer, sizeof(buffer));
1498
1499 DPRINT(("CRadeonProducer::Connect() - %s\n", buffer));
1500
1501 strcpy(io_name, fOutput.name);
1502
1503 startCapturing();
1504
1505 DPRINT(("CRadeonProducer::Connect() done\n"));
1506 }
1507
1508 void
Disconnect(const media_source & source,const media_destination & destination)1509 CRadeonProducer::Disconnect(const media_source &source,
1510 const media_destination &destination)
1511 {
1512 DPRINT(("Disconnect()\n"));
1513
1514 if( source != fOutput.source || destination != fOutput.destination ) {
1515 DPRINT(("Disconnect: Bad source and/or destination\n"));
1516 return;
1517 }
1518
1519 fOutput.destination = media_destination::null;
1520
1521 delete fBufferGroup;
1522 fBufferGroup = NULL;
1523
1524 fVideoIn.Stop();
1525
1526 RealTimeQueue()->FlushEvents( 0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HARDWARE );
1527
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;
1531
1532 DPRINT(("Disconnect() done\n"));
1533 }
1534
1535 void
LateNoticeReceived(const media_source & source,bigtime_t how_much,bigtime_t performance_time)1536 CRadeonProducer::LateNoticeReceived(const media_source &source,
1537 bigtime_t how_much, bigtime_t performance_time)
1538 {
1539 DPRINT(("CRadeonProducer::LateNoticeReceived()\n"));
1540
1541 TOUCH(source); TOUCH(how_much); TOUCH(performance_time);
1542 }
1543
1544 void
EnableOutput(const media_source & source,bool enabled,int32 * _deprecated_)1545 CRadeonProducer::EnableOutput(const media_source &source, bool enabled,
1546 int32 *_deprecated_)
1547 {
1548 DPRINT(("CRadeonProducer::EnableOutput()\n"));
1549
1550 TOUCH(_deprecated_);
1551
1552 if (source != fOutput.source)
1553 return;
1554
1555 fEnabled = enabled;
1556 }
1557
1558 status_t
SetPlayRate(int32 numer,int32 denom)1559 CRadeonProducer::SetPlayRate(int32 numer, int32 denom)
1560 {
1561 DPRINT(("CRadeonProducer::SetPlayRate()\n"));
1562
1563 TOUCH(numer); TOUCH(denom);
1564
1565 return B_ERROR;
1566 }
1567
1568 void
AdditionalBufferRequested(const media_source & source,media_buffer_id prev_buffer,bigtime_t prev_time,const media_seek_tag * prev_tag)1569 CRadeonProducer::AdditionalBufferRequested(const media_source &source,
1570 media_buffer_id prev_buffer, bigtime_t prev_time,
1571 const media_seek_tag *prev_tag)
1572 {
1573 DPRINT(("CRadeonProducer::AdditionalBufferRequested()\n"));
1574
1575 TOUCH(source); TOUCH(prev_buffer); TOUCH(prev_time); TOUCH(prev_tag);
1576 }
1577
1578 void
LatencyChanged(const media_source & source,const media_destination & destination,bigtime_t new_latency,uint32 flags)1579 CRadeonProducer::LatencyChanged(const media_source &source,
1580 const media_destination &destination, bigtime_t new_latency,
1581 uint32 flags)
1582 {
1583 DPRINT(("CRadeonProducer::LatencyChanged()\n"));
1584 BBufferProducer::LatencyChanged( source, destination, new_latency, flags );
1585 }
1586
1587
1588
1589 /* BControllable */
1590
1591 status_t
GetParameterValue(int32 id,bigtime_t * last_change,void * value,size_t * size)1592 CRadeonProducer::GetParameterValue(
1593 int32 id, bigtime_t *last_change, void *value, size_t *size)
1594 {
1595 DPRINT(("CRadeonProducer::GetParameterValue(%d)\n", id));
1596
1597 switch (id) {
1598 case P_SOURCE:
1599 *last_change = fSourceLastChange;
1600 *size = sizeof(fSource);
1601 *((uint32 *) value) = fSource;
1602 break;
1603 case P_STANDARD:
1604 *last_change = fStandardLastChange;
1605 *size = sizeof(fStandard);
1606 *((uint32 *) value) = fStandard;
1607 break;
1608 case P_MODE:
1609 *last_change = fModeLastChange;
1610 *size = sizeof(fMode);
1611 *((uint32 *) value) = fMode;
1612 break;
1613 case P_FORMAT:
1614 *last_change = fFormatLastChange;
1615 *size = sizeof(fFormat);
1616 *((uint32 *) value) = fFormat;
1617 break;
1618 case P_RESOLUTION:
1619 *last_change = fResolutionLastChange;
1620 *size = sizeof(fResolution);
1621 *((uint32 *) value) = fResolution;
1622 break;
1623 case P_TUNER:
1624 *last_change = fTunerLastChange;
1625 *size = sizeof(fTuner);
1626 *((uint32 *) value) = fTuner;
1627 break;
1628 case P_BRIGHTNESS:
1629 *last_change = fBrightnessLastChange;
1630 *size = sizeof(fBrightness);
1631 *((float *) value) = fBrightness;
1632 break;
1633 case P_CONTRAST:
1634 *last_change = fContrastLastChange;
1635 *size = sizeof(fContrast);
1636 *((float *) value) = fContrast;
1637 break;
1638 case P_SATURATION:
1639 *last_change = fSaturationLastChange;
1640 *size = sizeof(fSaturation);
1641 *((float *) value) = fSaturation;
1642 break;
1643 case P_HUE:
1644 *last_change = fHueLastChange;
1645 *size = sizeof(fHue);
1646 *((float *) value) = fHue;
1647 break;
1648 case P_SHARPNESS:
1649 *last_change = fSharpnessLastChange;
1650 *size = sizeof(fSharpness);
1651 *((float *) value) = fSharpness;
1652 break;
1653 default:
1654 DPRINT(("Unknown parameter\n"));
1655 return B_BAD_VALUE;
1656 }
1657
1658 return B_OK;
1659 }
1660
1661
1662 /*
1663 * Change video format instantly.
1664 *
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.
1670 */
1671 void
instantFormatChange(media_format * new_format)1672 CRadeonProducer::instantFormatChange( media_format *new_format )
1673 {
1674 if( fOutput.destination == media_destination::null )
1675 return;
1676
1677 if( finalizeFormat( new_format ) != B_OK ) {
1678 DPRINT(("Current format does not allow to change interlace mode on-the-fly\n"));
1679 return;
1680 }
1681
1682 if( ChangeFormat( fOutput.source, fOutput.destination, new_format ) != B_OK ) {
1683 DPRINT(("Consumer does not allow to change interlace mode instantly\n"));
1684 return;
1685 }
1686
1687 fOutput.format = *new_format;
1688 fCurMode = extractCaptureMode( new_format );
1689
1690 fVideoIn.Stop();
1691 startCapturing();
1692 }
1693
1694 void
SetParameterValue(int32 id,bigtime_t when,const void * value,size_t size)1695 CRadeonProducer::SetParameterValue(
1696 int32 id, bigtime_t when, const void *value, size_t size)
1697 {
1698 DPRINT(("CRadeonProducer::SetParameterValue()\n"));
1699
1700 if (!value || size != sizeof(uint32))
1701 return;
1702
1703 switch (id) {
1704 case P_SOURCE:
1705 if (*((const int32 *) value) == fSource)
1706 return;
1707 fSource = *((const uint32 *) value);
1708 fSourceLastChange = when;
1709
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;
1715
1716 break;
1717 case P_STANDARD: {
1718 if (*((const int32 *) value) == fStandard)
1719 return;
1720
1721 fStandard = BeToVideoInStandard( *((const int32 *) value) );
1722
1723 fStandardLastChange = when;
1724
1725 media_format new_format = fOutput.format;
1726
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;
1733
1734 instantFormatChange( &new_format );
1735 break; }
1736 case P_MODE: {
1737 if (*((const int32 *) value) == fMode)
1738 return;
1739
1740 fMode = *((const uint32 *) value);
1741 fModeLastChange = when;
1742
1743 media_format new_format = fOutput.format;
1744
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;
1749
1750 instantFormatChange( &new_format );
1751
1752 break; }
1753 case P_FORMAT: {
1754 if (*((const int32 *) value) == fFormat)
1755 return;
1756 fFormat = *((const uint32 *) value);
1757 fFormatLastChange = when;
1758
1759 media_format new_format = fOutput.format;
1760
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;
1763
1764 instantFormatChange( &new_format );
1765 break; }
1766 case P_RESOLUTION:
1767 if (*((const int32 *) value) == fResolution)
1768 return;
1769 fResolution = *((const uint32 *) value);
1770 fResolutionLastChange = when;
1771 // no live update - see instantFormatChange()
1772 break;
1773 case P_TUNER:
1774 if (*((const int32 *) value) == fTuner)
1775 return;
1776 fTuner = *((const uint32 *) value);
1777 fTunerLastChange = when;
1778 fVideoIn.SetChannel(fTuner, C_VIDEO_IN_NTSC); // was hardcoded to NTSC
1779 break;
1780 case P_BRIGHTNESS:
1781 if (*((const float *) value) == fBrightness)
1782 return;
1783 fBrightness = (int32)*((const float *) value);
1784 fBrightnessLastChange = when;
1785 fVideoIn.SetBrightness(fBrightness);
1786 break;
1787 case P_CONTRAST:
1788 if (*((const float *) value) == fContrast)
1789 return;
1790 fContrast = (int32)*((const float *) value);
1791 fContrastLastChange = when;
1792 fVideoIn.SetContrast(fContrast);
1793 break;
1794 case P_SATURATION:
1795 if (*((const float *) value) == fSaturation)
1796 return;
1797 fSaturation = (int32)*((const float *) value);
1798 fSaturationLastChange = when;
1799 fVideoIn.SetSaturation(fSaturation);
1800 break;
1801 case P_HUE:
1802 if (*((const float *) value) == fHue)
1803 return;
1804 fHue = (int32)*((const float *) value);
1805 fHueLastChange = when;
1806 fVideoIn.SetHue(fHue);
1807 break;
1808 case P_SHARPNESS:
1809 if (*((const float *) value) == fSharpness)
1810 return;
1811 fSharpness = (int32)*((const float *) value);
1812 fSharpnessLastChange = when;
1813 fVideoIn.SetSharpness(fSharpness);
1814 break;
1815 default:
1816 return;
1817 }
1818
1819 BroadcastNewParameterValue(when, id, const_cast<void *>(value), sizeof(uint32));
1820 }
1821
1822 status_t
StartControlPanel(BMessenger * out_messenger)1823 CRadeonProducer::StartControlPanel(BMessenger *out_messenger)
1824 {
1825 return BControllable::StartControlPanel(out_messenger);
1826 }
1827
AddInt32(BMessage * msg,EOptions option,int32 value)1828 status_t CRadeonProducer::AddInt32(
1829 BMessage *msg, EOptions option, int32 value )
1830 {
1831 char name[5];
1832
1833 *(int32 *)name = option;
1834 name[4] = 0;
1835
1836 return msg->AddInt32( name, value );
1837 }
1838
1839 status_t
GetConfiguration(BMessage * out)1840 CRadeonProducer::GetConfiguration( BMessage *out )
1841 {
1842 status_t res;
1843
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 )
1855 return res;
1856
1857 return B_OK;
1858 }
1859
1860
1861 /* VideoProducer */
1862
1863 void
HandleStart(bigtime_t performance_time)1864 CRadeonProducer::HandleStart(bigtime_t performance_time)
1865 {
1866 /* Start producing frames, even if the output hasn't been connected yet. */
1867 DPRINT(("CRadeonProducer::HandleStart()\n"));
1868
1869 if( RunState() != BMediaEventLooper::B_STOPPED ) {
1870 DPRINT(("already running\n"));
1871 return;
1872 }
1873
1874 SetRunState( BMediaEventLooper::B_STARTED );
1875
1876 startCapturing();
1877 }
1878
1879 void
HandleStop(void)1880 CRadeonProducer::HandleStop(void)
1881 {
1882 DPRINT(("CRadeonProducer::HandleStop()\n"));
1883
1884 fVideoIn.Stop();
1885
1886 // discard pending capture event
1887 RealTimeQueue()->FlushEvents( 0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HARDWARE );
1888 }
1889
1890 void
HandleTimeWarp(bigtime_t performance_time)1891 CRadeonProducer::HandleTimeWarp(bigtime_t performance_time)
1892 {
1893 DPRINT(("CRadeonProducer::HandleTimeWarp()\n"));
1894 }
1895
1896 void
HandleSeek(bigtime_t performance_time)1897 CRadeonProducer::HandleSeek(bigtime_t performance_time)
1898 {
1899 DPRINT(("CRadeonProducer::HandleSeek()\n"));
1900 }
1901
1902 void
captureField(bigtime_t * capture_time)1903 CRadeonProducer::captureField( bigtime_t *capture_time )
1904 {
1905 *capture_time = system_time();
1906
1907 // don't capture if output is disabled
1908 if (!fEnabled)
1909 return;
1910
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);
1914
1915 if (!buffer) {
1916 DPRINT(( "No buffer\n" ));
1917 return;
1918 }
1919
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;
1925 h->file_pos = 0;
1926 h->orig_size = 0;
1927 h->data_offset = 0;
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;
1932
1933 int field_sequence;
1934 short field_number;
1935
1936 int dropped=fVideoIn.Capture(
1937 fOutput.format.u.raw_video.display.format,
1938 buffer->Data(),
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,
1941 &field_sequence,
1942 &field_number,
1943 capture_time);
1944
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 );
1953
1954 h->u.raw_video.field_sequence = field_sequence - fFieldSequenceBase;
1955 h->u.raw_video.field_number = field_number;
1956
1957 if (dropped > 1) {
1958 PRINT(("%d frames dropped\n", dropped-1));
1959 }
1960
1961 if (SendBuffer(buffer, fOutput.destination) < B_OK) {
1962 PRINTF(-1, ("FrameGenerator: Error sending buffer\n"));
1963 buffer->Recycle();
1964 }
1965 }
1966
1967 void
HandleHardware()1968 CRadeonProducer::HandleHardware()
1969 {
1970 bigtime_t capture_time;
1971
1972 //DPRINT(("Hi\n"));
1973
1974 if( RunState() != BMediaEventLooper::B_STARTED )
1975 return;
1976
1977 captureField( &capture_time );
1978
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);
1983
1984 RealTimeQueue()->AddEvent(event);
1985 }
1986