2 * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de>. All rights reserved.
3 * Copyright (C) 2008 Maurice Kalinowski <haiku@kaldience.com>. All rights reserved.
5 * Distributed under the terms of the MIT License.
9 #include "VideoWindow.h"
14 #include <BufferGroup.h>
16 #include <MediaRoster.h>
18 #include <TimeSource.h>
24 VideoNode::VideoNode(const char *name
)
27 , BBufferConsumer(B_MEDIA_RAW_VIDEO
)
31 , fOverlayEnabled(true)
32 , fOverlayActive(false)
33 , fDirectOverlayBuffer(false)
35 , fBitmapLocker(new BLocker("Video Node Locker"))
37 , fInternalFlavorId(0)
43 VideoNode::VideoNode(const char *name
, BMediaAddOn
* addon
, int32 id
)
46 , BBufferConsumer(B_MEDIA_RAW_VIDEO
)
50 , fOverlayEnabled(true)
51 , fOverlayActive(false)
52 , fDirectOverlayBuffer(false)
54 , fBitmapLocker(new BLocker("Video Node Locker"))
56 , fInternalFlavorId(id
)
62 VideoNode::~VideoNode()
67 if (fWindow
&& fWindow
->Lock())
73 VideoNode::AddOn(int32
*internal_id
) const
75 *internal_id
= fInternalFlavorId
;
81 VideoNode::NodeRegistered()
84 fInput
.source
= media_source::null
;
85 fInput
.destination
.port
= ControlPort();
86 fInput
.destination
.id
= 0;
87 fInput
.format
.type
= B_MEDIA_RAW_VIDEO
;
88 fInput
.format
.u
.raw_video
= media_raw_video_format::wildcard
;
89 strcpy(fInput
.name
, "video in");
91 SetPriority(B_DISPLAY_PRIORITY
);
97 VideoNode::BufferReceived(BBuffer
* buffer
)
99 if (RunState() != B_STARTED
) {
103 if (fOverlayActive
&& fDirectOverlayBuffer
) {
104 HandleBuffer(buffer
);
106 media_timed_event
event(buffer
->Header()->start_time
,
107 BTimedEventQueue::B_HANDLE_BUFFER
, buffer
,
108 BTimedEventQueue::B_RECYCLE_BUFFER
);
109 EventQueue()->AddEvent(event
);
115 VideoNode::GetNextInput(int32
*cookie
, media_input
*out_input
)
127 VideoNode::DisposeInputCookie(int32 cookie
)
134 VideoNode:: HandleMessage(int32 message
, const void *data
, size_t size
)
141 VideoNode::HandleEvent(const media_timed_event
*event
, bigtime_t lateness
,
144 switch (event
->type
) {
145 case BTimedEventQueue::B_START
:
147 case BTimedEventQueue::B_STOP
:
148 EventQueue()->FlushEvents(event
->event_time
,
149 BTimedEventQueue::B_ALWAYS
, true,
150 BTimedEventQueue::B_HANDLE_BUFFER
);
152 case BTimedEventQueue::B_HANDLE_BUFFER
:
153 HandleBuffer((BBuffer
*)event
->pointer
);
155 case BTimedEventQueue::B_SEEK
:
156 fprintf(stderr
, "VideoNode::HandleEvent Seek event not handled\n");
159 fprintf(stderr
, "VideoNode::HandleEvent unknown event\n");
166 VideoNode::ProducerDataStatus(const media_destination
&dst
, int32 status
,
167 bigtime_t at_media_time
)
174 VideoNode::GetLatencyFor(const media_destination
&dst
, bigtime_t
*out_latency
,
175 media_node_id
*out_id
)
177 if (dst
!= fInput
.destination
)
178 return B_MEDIA_BAD_DESTINATION
;
180 *out_latency
= 10000;
181 *out_id
= TimeSource()->ID();
187 VideoNode::AcceptFormat(const media_destination
&dst
, media_format
*format
)
189 /* The connection process:
190 * BBufferProducer::FormatProposal
191 * we are here => BBufferConsumer::AcceptFormat
192 * BBufferProducer::PrepareToConnect
193 * BBufferConsumer::Connected
194 * BBufferProducer::Connect
196 if (dst
!= fInput
.destination
)
197 return B_MEDIA_BAD_DESTINATION
;
199 if (format
->type
== B_MEDIA_NO_TYPE
)
200 format
->type
= B_MEDIA_RAW_VIDEO
;
202 if (format
->type
!= B_MEDIA_RAW_VIDEO
)
203 return B_MEDIA_BAD_FORMAT
;
205 // In order to display video we need to create a buffer that is either
206 // in the overlay colorspace B_YCbCr422
207 // or the requested colorspace if not B_YCbCr422
208 // and we need to tell the node upstream of our choice
210 BRect
frame(0, 0, format
->u
.raw_video
.display
.line_width
,
211 format
->u
.raw_video
.display
.line_count
);
216 if (format
->u
.raw_video
.display
.format
== B_NO_COLOR_SPACE
) {
217 // upstream node is leaving it up to us so we try overlay then B_RGBA32 (We probably should try what format the screen is)
218 err
= CreateBuffers(frame
, B_YCbCr422
, true);
219 SetOverlayEnabled(err
== B_OK
);
220 if (!fOverlayEnabled
) {
221 // no overlay available so fall back to RGBA32
222 err
= CreateBuffers(frame
, B_RGBA32
, false);
224 } else if (format
->u
.raw_video
.display
.format
== B_YCbCr422
) {
225 // upstream node is likely requesting overlay
226 err
= CreateBuffers(frame
, B_YCbCr422
, true);
227 SetOverlayEnabled(err
== B_OK
);
228 // if we cannot give them what they want then return error
230 // upstream node is requesting some other format
231 SetOverlayEnabled(false);
232 err
= CreateBuffers(frame
, format
->u
.raw_video
.display
.format
, fOverlayEnabled
);
236 fprintf(stderr
, "VideoNode::Connected failed, fOverlayEnabled = %d\n",
240 format
->u
.raw_video
.display
.format
= fBitmap
->ColorSpace();
248 VideoNode::Connected(const media_source
&src
, const media_destination
&dst
,
249 const media_format
&format
, media_input
*out_input
)
251 /* The connection process:
252 * BBufferProducer::FormatProposal
253 * BBufferConsumer::AcceptFormat
254 * BBufferProducer::PrepareToConnect
255 * we are here => BBufferConsumer::Connected
256 * BBufferProducer::Connect
259 if (dst
!= fInput
.destination
)
260 return B_MEDIA_BAD_DESTINATION
;
263 fInput
.format
= format
;
265 if (fInput
.format
.u
.raw_video
.field_rate
< 1.0)
266 fInput
.format
.u
.raw_video
.field_rate
= 25.0;
275 VideoNode::Disconnected(const media_source
&src
, const media_destination
&dst
)
277 if (src
!= fInput
.source
)
279 if (dst
!= fInput
.destination
)
284 // disconnect the connection
285 fInput
.source
= media_source::null
;
290 VideoNode::FormatChanged(const media_source
&src
, const media_destination
&dst
,
291 int32 from_change_count
, const media_format
&format
)
293 if (src
!= fInput
.source
)
294 return B_MEDIA_BAD_SOURCE
;
295 if (dst
!= fInput
.destination
)
296 return B_MEDIA_BAD_DESTINATION
;
298 color_space colorspace
= format
.u
.raw_video
.display
.format
;
299 BRect
frame(0, 0, format
.u
.raw_video
.display
.line_width
- 1,
300 format
.u
.raw_video
.display
.line_count
- 1);
305 if (fOverlayEnabled
) {
306 fVideoView
->RemoveOverlay();
307 err
= CreateBuffers(frame
, colorspace
, true); // try overlay
309 fprintf(stderr
, "VideoNode::FormatChanged creating overlay buffer failed\n");
310 err
= CreateBuffers(frame
, colorspace
, false); // no overlay
313 err
= CreateBuffers(frame
, colorspace
, false); // no overlay
317 fprintf(stderr
, "VideoNode::FormatChanged failed (lost buffer group!)\n");
318 return B_MEDIA_BAD_FORMAT
;
321 fInput
.format
= format
;
328 VideoNode::HandleBuffer(BBuffer
*buffer
)
331 if (fBitmap
&& fWindow
&& fVideoView
) {
332 // bigtime_t start = system_time();
333 if (fOverlayActive
) {
334 if (B_OK
== fBitmap
->LockBits()) {
335 memcpy(fBitmap
->Bits(), buffer
->Data(), fBitmap
->BitsLength());
336 fBitmap
->UnlockBits();
339 memcpy(fBitmap
->Bits(), buffer
->Data(), fBitmap
->BitsLength());
341 // printf("overlay copy: %Ld usec\n", system_time() - start);
347 fVideoView
->DrawFrame();
352 VideoNode::SetOverlayEnabled(bool yesno
)
354 fOverlayEnabled
= yesno
;
359 VideoNode::LockBitmap()
361 fBitmapLocker
->Lock();
373 VideoNode::UnlockBitmap()
375 fBitmapLocker
->Unlock();
380 VideoNode::IsOverlayActive()
382 return fOverlayActive
;
387 VideoNode::CreateBuffers(BRect frame
, color_space cspace
, bool overlay
)
389 printf("VideoNode::CreateBuffers: frame %d,%d,%d,%d colorspace 0x%08x, "
390 "overlay %d\n", int(frame
.left
), int(frame
.top
), int(frame
.right
),
391 int(frame
.bottom
), int(cspace
), overlay
);
394 ASSERT(fBitmap
== 0);
398 flags
= B_BITMAP_WILL_OVERLAY
| B_BITMAP_RESERVE_OVERLAY_CHANNEL
;
400 fBitmap
= new BBitmap(frame
, flags
, cspace
);
401 if (!(fBitmap
&& fBitmap
->InitCheck() == B_OK
&& fBitmap
->IsValid())) {
404 fOverlayActive
= false;
406 fprintf(stderr
, "VideoNode::CreateBuffers failed\n");
407 return B_MEDIA_BAD_FORMAT
;
409 fOverlayActive
= overlay
;
417 VideoNode::DeleteBuffers()
427 VideoNode::_InitDisplay()
429 // TODO: Get rid of hardcoded values
430 BRect
size(0,0,320,240);
431 fVideoView
= new VideoView(size
, "Video View", B_FOLLOW_ALL_SIDES
,
432 B_WILL_DRAW
| B_FULL_UPDATE_ON_RESIZE
, this);
434 size
.OffsetBy(40.f
, 40.f
);
435 fWindow
= new VideoWindow(size
, fVideoView
);