1 /* 2 * VideoNode.cpp - "Video Window" media add-on. 3 * 4 * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de> 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * version 2 as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * 19 */ 20 #include <stdio.h> 21 #include <string.h> 22 #include <Window.h> 23 #include <TimeSource.h> 24 #include <MediaRoster.h> 25 #include <BufferGroup.h> 26 #include <Buffer.h> 27 #include <Bitmap.h> 28 #include <Locker.h> 29 #include <Debug.h> 30 31 #include "VideoNode.h" 32 #include "VideoView.h" 33 34 35 VideoNode::VideoNode(const char *name, VideoView *view) 36 : BMediaNode(name) 37 , BMediaEventLooper() 38 , BBufferConsumer(B_MEDIA_RAW_VIDEO) 39 , fVideoView(view) 40 , fInput() 41 , fOverlayEnabled(true) 42 , fOverlayActive(false) 43 , fDirectOverlayBuffer(false) 44 , fBitmap(0) 45 , fBitmapLocker(new BLocker("Video Node Locker")) 46 { 47 } 48 49 50 VideoNode::~VideoNode() 51 { 52 Quit(); 53 DeleteBuffers(); 54 delete fBitmapLocker; 55 } 56 57 58 BMediaAddOn * 59 VideoNode::AddOn(int32 *internal_id) const 60 { 61 *internal_id = 0; 62 return NULL; 63 } 64 65 66 void 67 VideoNode::NodeRegistered() 68 { 69 fInput.node = Node(); 70 fInput.source = media_source::null; 71 fInput.destination.port = ControlPort(); 72 fInput.destination.id = 0; 73 fInput.format.type = B_MEDIA_RAW_VIDEO; 74 fInput.format.u.raw_video = media_raw_video_format::wildcard; 75 strcpy(fInput.name, "video in"); 76 77 SetPriority(B_DISPLAY_PRIORITY); 78 Run(); 79 } 80 81 82 void 83 VideoNode::BufferReceived(BBuffer * buffer) 84 { 85 if (RunState() != B_STARTED) { 86 buffer->Recycle(); 87 return; 88 } 89 if (fOverlayActive && fDirectOverlayBuffer) { 90 HandleBuffer(buffer); 91 } else { 92 media_timed_event event(buffer->Header()->start_time, 93 BTimedEventQueue::B_HANDLE_BUFFER, 94 buffer, 95 BTimedEventQueue::B_RECYCLE_BUFFER); 96 EventQueue()->AddEvent(event); 97 } 98 } 99 100 101 status_t 102 VideoNode::GetNextInput(int32 *cookie, media_input *out_input) 103 { 104 if (*cookie < 1) { 105 *out_input = fInput; 106 *cookie += 1; 107 return B_OK; 108 } 109 return B_ERROR; 110 } 111 112 113 void 114 VideoNode::DisposeInputCookie(int32 cookie) 115 { 116 // nothing to do 117 } 118 119 120 status_t 121 VideoNode:: HandleMessage(int32 message, 122 const void *data, 123 size_t size) 124 { 125 return B_ERROR; 126 } 127 128 129 void 130 VideoNode::HandleEvent(const media_timed_event *event, 131 bigtime_t lateness, 132 bool realTimeEvent) 133 { 134 switch (event->type) { 135 case BTimedEventQueue::B_START: 136 break; 137 case BTimedEventQueue::B_STOP: 138 EventQueue()->FlushEvents(event->event_time, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER); 139 break; 140 case BTimedEventQueue::B_HANDLE_BUFFER: 141 HandleBuffer((BBuffer *)event->pointer); 142 break; 143 default: 144 printf("VideoNode::HandleEvent unknown event"); 145 break; 146 } 147 } 148 149 150 void 151 VideoNode::ProducerDataStatus(const media_destination &dst, 152 int32 status, 153 bigtime_t at_media_time) 154 { 155 // do nothing 156 } 157 158 159 status_t 160 VideoNode::GetLatencyFor(const media_destination &dst, 161 bigtime_t *out_latency, 162 media_node_id *out_id) 163 { 164 if (dst != fInput.destination) 165 return B_MEDIA_BAD_DESTINATION; 166 167 *out_latency = 10000; 168 *out_id = TimeSource()->ID(); 169 return B_OK; 170 } 171 172 status_t 173 VideoNode::AcceptFormat(const media_destination &dst, 174 media_format *format) 175 { 176 /* The connection process: 177 * BBufferProducer::FormatProposal 178 * we are here => BBufferConsumer::AcceptFormat 179 * BBufferProducer::PrepareToConnect 180 * BBufferConsumer::Connected 181 * BBufferProducer::Connect 182 */ 183 184 if (dst != fInput.destination) 185 return B_MEDIA_BAD_DESTINATION; 186 187 if (format->type == B_MEDIA_NO_TYPE) 188 format->type = B_MEDIA_RAW_VIDEO; 189 190 if (format->type != B_MEDIA_RAW_VIDEO) 191 return B_MEDIA_BAD_FORMAT; 192 193 194 return B_OK; 195 } 196 197 198 status_t 199 VideoNode::Connected(const media_source &src, 200 const media_destination &dst, 201 const media_format &format, 202 media_input *out_input) 203 { 204 /* The connection process: 205 * BBufferProducer::FormatProposal 206 * BBufferConsumer::AcceptFormat 207 * BBufferProducer::PrepareToConnect 208 * we are here => BBufferConsumer::Connected 209 * BBufferProducer::Connect 210 */ 211 212 if (dst != fInput.destination) 213 return B_MEDIA_BAD_DESTINATION; 214 215 fInput.source = src; 216 fInput.format = format; 217 218 if (fInput.format.u.raw_video.field_rate < 1.0) 219 fInput.format.u.raw_video.field_rate = 25.0; 220 221 color_space colorspace = format.u.raw_video.display.format; 222 BRect frame(0, 0, format.u.raw_video.display.line_width - 1, format.u.raw_video.display.line_count - 1); 223 status_t err; 224 225 DeleteBuffers(); 226 err = CreateBuffers(frame, colorspace, fOverlayEnabled); 227 if (err) { 228 printf("VideoNode::Connected failed, fOverlayEnabled = %d\n", fOverlayEnabled); 229 return err; 230 } 231 232 *out_input = fInput; 233 234 return B_OK; 235 236 } 237 238 239 void 240 VideoNode::Disconnected(const media_source &src, 241 const media_destination &dst) 242 { 243 if (src != fInput.source) 244 return; 245 if (dst != fInput.destination) 246 return; 247 248 DeleteBuffers(); 249 250 // disconnect the connection 251 fInput.source = media_source::null; 252 } 253 254 255 status_t 256 VideoNode::FormatChanged(const media_source &src, 257 const media_destination &dst, 258 int32 from_change_count, 259 const media_format &format) 260 { 261 printf("VideoNode::FormatChanged enter\n"); 262 if (src != fInput.source) 263 return B_MEDIA_BAD_SOURCE; 264 if (dst != fInput.destination) 265 return B_MEDIA_BAD_DESTINATION; 266 267 color_space colorspace = format.u.raw_video.display.format; 268 BRect frame(0, 0, format.u.raw_video.display.line_width - 1, format.u.raw_video.display.line_count - 1); 269 status_t err; 270 271 DeleteBuffers(); 272 if (fOverlayEnabled) { 273 fVideoView->RemoveOverlay(); 274 err = CreateBuffers(frame, colorspace, true); // try overlay 275 if (err) { 276 printf("VideoNode::FormatChanged creating overlay buffer failed\n"); 277 err = CreateBuffers(frame, colorspace, false); // no overlay 278 } 279 } else { 280 err = CreateBuffers(frame, colorspace, false); // no overlay 281 } 282 if (err) { 283 printf("VideoNode::FormatChanged failed (lost buffer group!)\n"); 284 return B_MEDIA_BAD_FORMAT; 285 } 286 287 fInput.format = format; 288 289 printf("VideoNode::FormatChanged leave\n"); 290 return B_OK; 291 } 292 293 294 void 295 VideoNode::HandleBuffer(BBuffer *buffer) 296 { 297 // printf("VideoNode::HandleBuffer\n"); 298 299 LockBitmap(); 300 if (fBitmap) { 301 // bigtime_t start = system_time(); 302 if (fOverlayActive) { 303 if (B_OK == fBitmap->LockBits()) { 304 memcpy(fBitmap->Bits(), buffer->Data(), fBitmap->BitsLength()); 305 fBitmap->UnlockBits(); 306 } 307 } else { 308 memcpy(fBitmap->Bits(), buffer->Data(), fBitmap->BitsLength()); 309 } 310 // printf("overlay copy: %Ld usec\n", system_time() - start); 311 } 312 UnlockBitmap(); 313 314 buffer->Recycle(); 315 316 fVideoView->DrawFrame(); 317 } 318 319 320 void 321 VideoNode::SetOverlayEnabled(bool yesno) 322 { 323 fOverlayEnabled = yesno; 324 } 325 326 327 void 328 VideoNode::LockBitmap() 329 { 330 fBitmapLocker->Lock(); 331 } 332 333 334 BBitmap * 335 VideoNode::Bitmap() 336 { 337 return fBitmap; 338 } 339 340 341 void 342 VideoNode::UnlockBitmap() 343 { 344 fBitmapLocker->Unlock(); 345 } 346 347 348 bool 349 VideoNode::IsOverlayActive() 350 { 351 return fOverlayActive; 352 } 353 354 355 status_t 356 VideoNode::CreateBuffers(BRect frame, color_space cspace, bool overlay) 357 { 358 printf("VideoNode::CreateBuffers: frame %d,%d,%d,%d colorspace 0x%08x, overlay %d\n", 359 int(frame.left), int(frame.top), int(frame.right), int(frame.bottom), int(cspace), overlay); 360 361 LockBitmap(); 362 ASSERT(fBitmap == 0); 363 uint32 flags = overlay ? (B_BITMAP_WILL_OVERLAY | B_BITMAP_RESERVE_OVERLAY_CHANNEL) : 0; 364 fBitmap = new BBitmap(frame, flags, cspace); 365 if (!(fBitmap && fBitmap->InitCheck() == B_OK && fBitmap->IsValid())) { 366 delete fBitmap; 367 fBitmap = 0; 368 fOverlayActive = false; 369 UnlockBitmap(); 370 printf("VideoNode::CreateBuffers failed\n"); 371 return B_ERROR; 372 } 373 fOverlayActive = overlay; 374 UnlockBitmap(); 375 printf("VideoNode::CreateBuffers success\n"); 376 return B_OK; 377 } 378 379 380 void 381 VideoNode::DeleteBuffers() 382 { 383 LockBitmap(); 384 delete fBitmap; 385 fBitmap = NULL; 386 UnlockBitmap(); 387 } 388