1 /* 2 * Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de> 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without restriction, 7 * including without limitation the rights to use, copy, modify, 8 * merge, publish, distribute, sublicense, and/or sell copies of 9 * the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 #include <stdio.h> 26 #include <string.h> 27 #include <Window.h> 28 #include <TimeSource.h> 29 #include <MediaRoster.h> 30 #include <BufferGroup.h> 31 #include <Buffer.h> 32 #include <Bitmap.h> 33 #include <Locker.h> 34 #include <Debug.h> 35 36 #include "VideoNode.h" 37 #include "VideoView.h" 38 39 void 40 overlay_copy(uint32 lines, void *dst, uint32 dst_bpr, const void *src, uint32 src_bpr) 41 { 42 // bigtime_t start = system_time(); 43 int len = min_c(dst_bpr, src_bpr); 44 // int len4 = len / 4; 45 while (lines--) { 46 /* 47 // this does not copy the last few bytes, if length is not aligned to 4 bytes 48 asm ("rep\n\t""movsl" 49 : 50 : "c" (len4), "S" (src), "D" (dst) 51 : "eax"); 52 */ 53 /* 54 const uint32 *s4 = (const uint32 *)src; 55 uint32 *d4 = (uint32 *)dst; 56 for (int i = 0; i < len4; i++) 57 d4[i] = s4[i]; 58 */ 59 /* 60 const uint8 *s1 = (const uint8 *)s4; 61 uint8 *d1 = (uint8 *)d4; 62 int l1 = len1; 63 while (l1--) 64 *d1++ = *s1++; 65 */ 66 memcpy(dst, src, len); 67 src = (char *)src + src_bpr; 68 dst = (char *)dst + dst_bpr; 69 } 70 // printf("overlay copy: %.06f sec\n", (system_time() - start) / 1000000.0); 71 } 72 73 74 VideoNode::VideoNode(const char *name, VideoView *view) 75 : BMediaNode(name) 76 , BMediaEventLooper() 77 , BBufferConsumer(B_MEDIA_RAW_VIDEO) 78 , fVideoView(view) 79 , fInput() 80 , fOverlayEnabled(true) 81 , fOverlayActive(false) 82 , fDirectOverlayBuffer(false) 83 , fBitmap(0) 84 , fBitmapLocker(new BLocker("Video Node Locker")) 85 { 86 } 87 88 89 VideoNode::~VideoNode() 90 { 91 Quit(); 92 DeleteBuffers(); 93 delete fBitmapLocker; 94 } 95 96 97 BMediaAddOn * 98 VideoNode::AddOn(int32 *internal_id) const 99 { 100 *internal_id = 0; 101 return NULL; 102 } 103 104 105 void 106 VideoNode::NodeRegistered() 107 { 108 fInput.node = Node(); 109 fInput.source = media_source::null; 110 fInput.destination.port = ControlPort(); 111 fInput.destination.id = 0; 112 fInput.format.type = B_MEDIA_RAW_VIDEO; 113 fInput.format.u.raw_video = media_raw_video_format::wildcard; 114 strcpy(fInput.name, "video in"); 115 116 SetPriority(B_DISPLAY_PRIORITY); 117 Run(); 118 } 119 120 121 void 122 VideoNode::BufferReceived(BBuffer * buffer) 123 { 124 if (RunState() != B_STARTED) { 125 buffer->Recycle(); 126 return; 127 } 128 if (fOverlayActive && fDirectOverlayBuffer) { 129 HandleBuffer(buffer); 130 } else { 131 media_timed_event event(buffer->Header()->start_time, 132 BTimedEventQueue::B_HANDLE_BUFFER, 133 buffer, 134 BTimedEventQueue::B_RECYCLE_BUFFER); 135 EventQueue()->AddEvent(event); 136 } 137 } 138 139 140 status_t 141 VideoNode::GetNextInput(int32 *cookie, media_input *out_input) 142 { 143 if (*cookie < 1) { 144 *out_input = fInput; 145 *cookie += 1; 146 return B_OK; 147 } 148 return B_ERROR; 149 } 150 151 152 void 153 VideoNode::DisposeInputCookie(int32 cookie) 154 { 155 // nothing to do 156 } 157 158 159 status_t 160 VideoNode:: HandleMessage(int32 message, 161 const void *data, 162 size_t size) 163 { 164 return B_ERROR; 165 } 166 167 168 void 169 VideoNode::HandleEvent(const media_timed_event *event, 170 bigtime_t lateness, 171 bool realTimeEvent) 172 { 173 switch (event->type) { 174 case BTimedEventQueue::B_START: 175 break; 176 case BTimedEventQueue::B_STOP: 177 EventQueue()->FlushEvents(event->event_time, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER); 178 break; 179 case BTimedEventQueue::B_HANDLE_BUFFER: 180 HandleBuffer((BBuffer *)event->pointer); 181 break; 182 default: 183 printf("VideoNode::HandleEvent unknown event"); 184 break; 185 } 186 } 187 188 189 void 190 VideoNode::ProducerDataStatus(const media_destination &dst, 191 int32 status, 192 bigtime_t at_media_time) 193 { 194 // do nothing 195 } 196 197 198 status_t 199 VideoNode::GetLatencyFor(const media_destination &dst, 200 bigtime_t *out_latency, 201 media_node_id *out_id) 202 { 203 if (dst != fInput.destination) 204 return B_MEDIA_BAD_DESTINATION; 205 206 *out_latency = 10000; 207 *out_id = TimeSource()->ID(); 208 return B_OK; 209 } 210 211 status_t 212 VideoNode::AcceptFormat(const media_destination &dst, 213 media_format *format) 214 { 215 /* The connection process: 216 * BBufferProducer::FormatProposal 217 * we are here => BBufferConsumer::AcceptFormat 218 * BBufferProducer::PrepareToConnect 219 * BBufferConsumer::Connected 220 * BBufferProducer::Connect 221 */ 222 223 if (dst != fInput.destination) 224 return B_MEDIA_BAD_DESTINATION; 225 226 if (format->type == B_MEDIA_NO_TYPE) 227 format->type = B_MEDIA_RAW_VIDEO; 228 229 if (format->type != B_MEDIA_RAW_VIDEO) 230 return B_MEDIA_BAD_FORMAT; 231 232 233 return B_OK; 234 } 235 236 237 status_t 238 VideoNode::Connected(const media_source &src, 239 const media_destination &dst, 240 const media_format &format, 241 media_input *out_input) 242 { 243 /* The connection process: 244 * BBufferProducer::FormatProposal 245 * BBufferConsumer::AcceptFormat 246 * BBufferProducer::PrepareToConnect 247 * we are here => BBufferConsumer::Connected 248 * BBufferProducer::Connect 249 */ 250 251 if (dst != fInput.destination) 252 return B_MEDIA_BAD_DESTINATION; 253 254 fInput.source = src; 255 fInput.format = format; 256 257 if (fInput.format.u.raw_video.field_rate < 1.0) 258 fInput.format.u.raw_video.field_rate = 25.0; 259 260 color_space colorspace = format.u.raw_video.display.format; 261 BRect frame(0, 0, format.u.raw_video.display.line_width - 1, format.u.raw_video.display.line_count - 1); 262 status_t err; 263 264 DeleteBuffers(); 265 err = CreateBuffers(frame, colorspace, fOverlayEnabled); 266 if (err) { 267 printf("VideoNode::Connected failed, fOverlayEnabled = %d\n", fOverlayEnabled); 268 return err; 269 } 270 271 *out_input = fInput; 272 273 return B_OK; 274 275 } 276 277 278 void 279 VideoNode::Disconnected(const media_source &src, 280 const media_destination &dst) 281 { 282 if (src != fInput.source) 283 return; 284 if (dst != fInput.destination) 285 return; 286 287 DeleteBuffers(); 288 289 // disconnect the connection 290 fInput.source = media_source::null; 291 } 292 293 294 status_t 295 VideoNode::FormatChanged(const media_source &src, 296 const media_destination &dst, 297 int32 from_change_count, 298 const media_format &format) 299 { 300 printf("VideoNode::FormatChanged enter\n"); 301 if (src != fInput.source) 302 return B_MEDIA_BAD_SOURCE; 303 if (dst != fInput.destination) 304 return B_MEDIA_BAD_DESTINATION; 305 306 color_space colorspace = format.u.raw_video.display.format; 307 BRect frame(0, 0, format.u.raw_video.display.line_width - 1, format.u.raw_video.display.line_count - 1); 308 status_t err; 309 310 DeleteBuffers(); 311 if (fOverlayEnabled) { 312 fVideoView->RemoveOverlay(); 313 err = CreateBuffers(frame, colorspace, true); // try overlay 314 if (err) { 315 printf("VideoNode::FormatChanged creating overlay buffer failed\n"); 316 err = CreateBuffers(frame, colorspace, false); // no overlay 317 } 318 } else { 319 err = CreateBuffers(frame, colorspace, false); // no overlay 320 } 321 if (err) { 322 printf("VideoNode::FormatChanged failed (lost buffer group!)\n"); 323 return B_MEDIA_BAD_FORMAT; 324 } 325 326 fInput.format = format; 327 328 printf("VideoNode::FormatChanged leave\n"); 329 return B_OK; 330 } 331 332 333 void 334 VideoNode::HandleBuffer(BBuffer *buffer) 335 { 336 // printf("VideoNode::HandleBuffer\n"); 337 338 LockBitmap(); 339 if (fBitmap) { 340 // bigtime_t start = system_time(); 341 if (fOverlayActive) { 342 if (B_OK == fBitmap->LockBits()) { 343 344 // memcpy(fBitmap->Bits(), buffer->Data(), fBitmap->BitsLength()); 345 346 // fBitmap->SetBits(buffer->Data(), fBitmap->BitsLength(), 0, fInput.format.u.raw_video.display.format); 347 348 overlay_copy(fBitmap->Bounds().IntegerHeight() + 1, 349 fBitmap->Bits(), fBitmap->BytesPerRow(), 350 buffer->Data(), fInput.format.u.raw_video.display.bytes_per_row); 351 352 353 fBitmap->UnlockBits(); 354 } 355 } else { 356 // memcpy(fBitmap->Bits(), buffer->Data(), fBitmap->BitsLength()); 357 358 overlay_copy(fBitmap->Bounds().IntegerHeight() + 1, 359 fBitmap->Bits(), fBitmap->BytesPerRow(), 360 buffer->Data(), fInput.format.u.raw_video.display.bytes_per_row); 361 } 362 // printf("overlay copy: %Ld usec\n", system_time() - start); 363 } 364 UnlockBitmap(); 365 366 buffer->Recycle(); 367 368 fVideoView->DrawFrame(); 369 } 370 371 372 void 373 VideoNode::SetOverlayEnabled(bool yesno) 374 { 375 fOverlayEnabled = yesno; 376 } 377 378 379 void 380 VideoNode::LockBitmap() 381 { 382 fBitmapLocker->Lock(); 383 } 384 385 386 BBitmap * 387 VideoNode::Bitmap() 388 { 389 return fBitmap; 390 } 391 392 393 void 394 VideoNode::UnlockBitmap() 395 { 396 fBitmapLocker->Unlock(); 397 } 398 399 400 bool 401 VideoNode::IsOverlayActive() 402 { 403 return fOverlayActive; 404 } 405 406 407 status_t 408 VideoNode::CreateBuffers(BRect frame, color_space cspace, bool overlay) 409 { 410 printf("VideoNode::CreateBuffers: frame %d,%d,%d,%d colorspace 0x%08x, overlay %d\n", 411 int(frame.left), int(frame.top), int(frame.right), int(frame.bottom), int(cspace), overlay); 412 413 // int32 bytesPerRow = B_ANY_BYTES_PER_ROW; 414 // if (cspace == B_YCbCr422) 415 // bytesPerRow = (int(frame.Width()) + 1) * 2; 416 417 // printf("overlay bitmap: requesting: bytes per row: %d\n", bytesPerRow); 418 419 LockBitmap(); 420 ASSERT(fBitmap == 0); 421 uint32 flags = overlay ? (B_BITMAP_WILL_OVERLAY | B_BITMAP_RESERVE_OVERLAY_CHANNEL) : 0; 422 // fBitmap = new BBitmap(frame, flags, cspace, bytesPerRow); 423 fBitmap = new BBitmap(frame, flags, cspace); 424 if (!(fBitmap && fBitmap->InitCheck() == B_OK && fBitmap->IsValid())) { 425 delete fBitmap; 426 fBitmap = 0; 427 fOverlayActive = false; 428 UnlockBitmap(); 429 printf("VideoNode::CreateBuffers failed\n"); 430 return B_ERROR; 431 } 432 printf("overlay bitmap: got: bytes per row: %ld\n", fBitmap->BytesPerRow()); 433 fOverlayActive = overlay; 434 UnlockBitmap(); 435 printf("VideoNode::CreateBuffers success\n"); 436 return B_OK; 437 } 438 439 440 void 441 VideoNode::DeleteBuffers() 442 { 443 LockBitmap(); 444 delete fBitmap; 445 fBitmap = NULL; 446 UnlockBitmap(); 447 } 448