1/* 2 * XvidDecoder.cpp - XviD plugin for the Haiku Operating System 3 * 4 * Copyright (C) 2007 Stephan A��mus <superstippi@gmx.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#define DEBUG 0 21#define PROPER_SEEKING 0 22#define PRINT_FOURCC 0 23 24#define MIN_USEFUL_BYTES 1 25 26#include "XvidDecoder.h" 27 28//#include <fenv.h> 29#include <new> 30#include <setjmp.h> 31#include <signal.h> 32#include <string.h> 33 34#include <ByteOrder.h> 35#include <Debug.h> 36#include <MediaTrack.h> 37#include <OS.h> 38 39#include <MediaDefs.h> 40#include <File.h> 41#include <Bitmap.h> 42 43#include "supported_codecs.h" 44 45 46using std::nothrow; 47 48 49#if DEBUG 50static const char* 51media_type_name(int type) 52{ 53 switch (type) { 54 case B_MEDIA_NO_TYPE: 55 return "B_MEDIA_NO_TYPE"; 56 case B_MEDIA_RAW_AUDIO: 57 return "B_MEDIA_RAW_AUDIO"; 58 case B_MEDIA_RAW_VIDEO: 59 return "B_MEDIA_RAW_VIDEO"; 60 case B_MEDIA_VBL: 61 return "B_MEDIA_VBL"; 62 case B_MEDIA_TIMECODE: 63 return "B_MEDIA_TIMECODE"; 64 case B_MEDIA_MIDI: 65 return "B_MEDIA_MIDI"; 66 case B_MEDIA_TEXT: 67 return "B_MEDIA_TEXT"; 68 case B_MEDIA_HTML: 69 return "B_MEDIA_HTML"; 70 case B_MEDIA_MULTISTREAM: 71 return "B_MEDIA_MULTISTREAM"; 72 case B_MEDIA_PARAMETERS: 73 return "B_MEDIA_PARAMETERS"; 74 case B_MEDIA_ENCODED_AUDIO: 75 return "B_MEDIA_ENCODED_AUDIO"; 76 case B_MEDIA_ENCODED_VIDEO: 77 return "B_MEDIA_ENCODED_VIDEO"; 78 79 case B_MEDIA_UNKNOWN_TYPE: 80 default: 81 return "B_MEDIA_UNKNOWN_TYPE"; 82 } 83} 84 85static char 86make_printable_char(uchar c) 87{ 88 if (c >= 0x20 && c < 0x7F) 89 return c; 90 return '.'; 91} 92 93static void 94print_hex(unsigned char* buff, int len) 95{ 96 int i, j; 97 for(i=0; i<len+7;i+=8) { 98 for (j=0; j<8; j++) { 99 if (i+j < len) 100 printf("%02X", buff[i+j]); 101 else 102 printf(" "); 103 if (j==3) 104 printf(" "); 105 } 106 printf("\t"); 107 for (j=0; j<8; j++) { 108 if (i+j < len) 109 printf("%c", make_printable_char(buff[i+j])); 110 else 111 printf(" "); 112 } 113 printf("\n"); 114 } 115} 116 117static void 118print_media_header(media_header* mh) 119{ 120 printf("media_header {%s, size_used: %ld, start_time: %lld (%02d:%02d.%02d), " 121 "field_sequence=%lu, user_data_type: .4s, file_pos: %ld, orig_size: %ld, " 122 "data_offset: %ld}\n", 123 media_type_name(mh->type), mh->size_used, mh->start_time, 124 int((mh->start_time / 60000000) % 60), 125 int((mh->start_time / 1000000) % 60), 126 int((mh->start_time / 10000) % 100), 127 (long)mh->u.raw_video.field_sequence, 128 //&(mh->user_data_type), 129 (long)mh->file_pos, 130 (long)mh->orig_size, 131 mh->data_offset); 132} 133 134static void 135print_media_decode_info(media_decode_info *info) 136{ 137 if (info) { 138 printf("media_decode_info {time_to_decode: %lld, " 139 "file_format_data_size: %ld, codec_data_size: %ld}\n", 140 info->time_to_decode, info->file_format_data_size, 141 info->codec_data_size); 142 } else 143 printf("media_decode_info (null)\n"); 144} 145#endif // DEBUG 146 147 148// #pragma mark - 149 150 151XvidDecoder::XvidDecoder() 152 : Decoder() 153 , fInputFormat() 154 , fOutputVideoFormat() 155 156 , fXvidDecoderHandle(NULL) 157 , fXvidColorspace(0) 158 159 , fFrame(0) 160 , fIndexInCodecTable(-1) 161 162 , fChunkBuffer(NULL) 163 , fWrappedChunkBuffer(NULL) 164 , fChunkBufferHandle(NULL) 165 , fChunkBufferSize(0) 166 , fLeftInChunkBuffer(0) 167 , fDiscontinuity(false) 168{ 169} 170 171 172XvidDecoder::~XvidDecoder() 173{ 174 _XvidUninit(); 175 delete[] fWrappedChunkBuffer; 176} 177 178 179void 180XvidDecoder::GetCodecInfo(media_codec_info* mci) 181{ 182 PRINT(("XvidDecoder::GetCodecInfo()\n")); 183 184 if (mci == NULL) 185 return;// B_BAD_VALUE; 186 187 if (fIndexInCodecTable < 0) 188 return;// B_NO_INIT; 189 190 sprintf(mci->short_name, "xvid"); 191 sprintf(mci->pretty_name, "xvid - %s", 192 gCodecTable[fIndexInCodecTable].prettyName); 193 194 mci->id = 0; 195 mci->sub_id = 0; 196 197 return;// B_OK; 198} 199 200 201status_t 202XvidDecoder::Setup(media_format* inputFormat, const void* inInfo, 203 size_t inSize) 204{ 205 if (inputFormat == NULL) 206 return B_BAD_VALUE; 207 208 if (inputFormat->type != B_MEDIA_ENCODED_VIDEO) 209 return B_BAD_VALUE; 210 211// PRINT(("%p->XvidDecoder::Setup()\n", this)); 212 213//#if DEBUG 214// char buffer[1024]; 215// string_for_format(*inputFormat, buffer, sizeof(buffer)); 216// PRINT((" inputFormat=%s\n", buffer)); 217// PRINT((" inSize=%d\n", inSize)); 218// print_hex((uchar*)inInfo, inSize); 219// PRINT((" user_data_type=%08lx\n", (int)inputFormat->user_data_type)); 220// print_hex((uchar*)inputFormat->user_data, 48); 221//#endif 222 223 uint32 codecID = 0; 224 media_format_family familyID = B_ANY_FORMAT_FAMILY; 225 226 // hacky... get the exact 4CC from there if it's in, to help xvid 227 // handle broken files 228// if ((inputFormat->user_data_type == B_CODEC_TYPE_INFO) 229// && !memcmp(inputFormat->user_data, "AVI ", 4)) { 230// codecID = ((uint32*)inputFormat->user_data)[1]; 231// familyID = B_AVI_FORMAT_FAMILY; 232// PRINT(("XvidDecoder::Setup() - AVI 4CC: %4s\n", 233// inputFormat->user_data + 4)); 234// } 235 236 if (codecID == 0) { 237 BMediaFormats formats; 238 media_format_description descr; 239 if (formats.GetCodeFor(*inputFormat, B_QUICKTIME_FORMAT_FAMILY, 240 &descr) == B_OK) { 241 codecID = descr.u.quicktime.codec; 242 familyID = B_QUICKTIME_FORMAT_FAMILY; 243 244 #if PRINT_FOURCC 245 uint32 bigEndianID = B_HOST_TO_BENDIAN_INT32(codecID); 246 printf("%p->XvidDecoder::Setup() - QT 4CC: %.4s\n", this, 247 (const char*)&bigEndianID); 248 #endif 249 } else if (formats.GetCodeFor(*inputFormat, B_AVI_FORMAT_FAMILY, 250 &descr) == B_OK) { 251 codecID = descr.u.avi.codec; 252 familyID = B_AVI_FORMAT_FAMILY; 253 254 #if PRINT_FOURCC 255 uint32 bigEndianID = B_HOST_TO_BENDIAN_INT32(codecID); 256 printf("%p->XvidDecoder::Setup() - AVI 4CC: %.4s\n", this, 257 (const char*)&bigEndianID); 258 #endif 259 } else if (formats.GetCodeFor(*inputFormat, B_MPEG_FORMAT_FAMILY, 260 &descr) == B_OK) { 261 codecID = descr.u.mpeg.id; 262 familyID = B_MPEG_FORMAT_FAMILY; 263 264 #if PRINT_FOURCC 265 printf("%p->XvidDecoder::Setup() - MPEG ID: %ld\n", this, codecID); 266 #endif 267 } 268 } 269 270 if (codecID == 0) 271 return B_ERROR; 272 273 for (int32 i = 0; i < gSupportedCodecsCount; i++) { 274 if (gCodecTable[i].family == familyID 275 && gCodecTable[i].fourcc == codecID) { 276 PRINT(("%p->XvidDecoder::Setup() - found codec in the table " 277 "at %ld.\n", this, i)); 278 fIndexInCodecTable = i; 279 fInputFormat = *inputFormat; 280 return B_OK; 281 } 282 } 283 284 #if PRINT_FOURCC 285 printf("%p->XvidDecoder::Setup() - no matching codec found in the " 286 "table.\n", this); 287 #endif 288 289 return B_ERROR; 290} 291 292 293status_t 294XvidDecoder::NegotiateOutputFormat(media_format* _inoutFormat) 295{ 296 PRINT(("%p->XvidDecoder::NegotiateOutputFormat()\n", this)); 297 298 if (_inoutFormat == NULL) 299 return B_BAD_VALUE; 300 301#if DEBUG 302 char buffer[1024]; 303 buffer[0] = 0; 304 if (string_for_format(*_inoutFormat, buffer, sizeof(buffer)) == B_OK) 305 PRINT((" _inoutFormat = %s\n", buffer)); 306#endif 307 308 // init our own output format from the sniffed values 309 fOutputVideoFormat = fInputFormat.u.encoded_video.output; 310 311 // suggest a default colorspace 312 color_space askedFormat = _inoutFormat->u.raw_video.display.format; 313 color_space supportedFormat; 314 uint32 bpr; 315 switch (askedFormat) { 316 case B_NO_COLOR_SPACE: 317 // suggest preferred format 318 case B_YCbCr422: 319 supportedFormat = B_YCbCr422; 320 fXvidColorspace = XVID_CSP_YUY2; 321 bpr = fOutputVideoFormat.display.line_width * 2; 322 break; 323 case B_YCbCr420: 324 supportedFormat = askedFormat; 325 fXvidColorspace = XVID_CSP_I420; 326 bpr = fOutputVideoFormat.display.line_width 327 + (fOutputVideoFormat.display.line_width + 1) / 2; 328 break; 329 case B_RGB32_BIG: 330 supportedFormat = askedFormat; 331 fXvidColorspace = XVID_CSP_RGBA; 332 bpr = fOutputVideoFormat.display.line_width * 4; 333 break; 334 case B_RGB24: 335 supportedFormat = askedFormat; 336 fXvidColorspace = XVID_CSP_BGR; 337 bpr = fOutputVideoFormat.display.line_width * 3; 338 break; 339 case B_RGB16: 340 supportedFormat = askedFormat; 341 fXvidColorspace = XVID_CSP_RGB565; 342 bpr = fOutputVideoFormat.display.line_width * 2; 343 break; 344 case B_RGB15: 345 supportedFormat = askedFormat; 346 fXvidColorspace = XVID_CSP_RGB555; 347 bpr = fOutputVideoFormat.display.line_width * 2; 348 break; 349 350 default: 351 fprintf(stderr, "XvidDecoder::NegotiateOutputFormat() - Application " 352 "asked for unsupported colorspace, using fallback " 353 "of B_RGB32.\n"); 354 case B_RGB32: 355 supportedFormat = B_RGB32; 356 fXvidColorspace = XVID_CSP_BGRA; 357 bpr = fOutputVideoFormat.display.line_width * 4; 358 break; 359 } 360 361 // enforce the colorspace we support 362 fOutputVideoFormat.display.format = supportedFormat; 363 _inoutFormat->u.raw_video.display.format = supportedFormat; 364 365 // enforce supported bytes per row 366 bpr = max_c(_inoutFormat->u.raw_video.display.bytes_per_row, 367 ((bpr + 3) / 4) * 4); 368 fOutputVideoFormat.display.bytes_per_row = bpr; 369 _inoutFormat->u.raw_video.display.bytes_per_row = bpr; 370 371 _inoutFormat->type = B_MEDIA_RAW_VIDEO; 372 _inoutFormat->u.raw_video = fOutputVideoFormat; 373 _inoutFormat->require_flags = 0; 374 _inoutFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 375 376#if DEBUG 377 if (string_for_format(*_inoutFormat, buffer, sizeof(buffer)) == B_OK) 378 PRINT(("%p->XvidDecoder: out_format=%s\n", this, buffer)); 379#endif 380 381 return _XvidInit() == 0 ? B_OK : B_ERROR; 382} 383 384 385status_t 386XvidDecoder::Decode(void* outBuffer, int64* outFrameCount, media_header* mh, 387 media_decode_info* info) 388{ 389 if (outBuffer == NULL || outFrameCount == NULL || mh == NULL) 390 return B_BAD_VALUE; 391 392// PRINT((%p->"XvidDecoder::Decode()\n", this)); 393 394 *outFrameCount = 0; 395 396 // are we in a hurry ? 397 bool hurryUp = (!info || (info->time_to_decode > 0)) ? false : true; 398 399 mh->type = B_MEDIA_UNKNOWN_TYPE; 400 mh->start_time = 0; 401 mh->size_used = 0; 402 mh->file_pos = 0; 403 mh->orig_size = 0; 404 mh->data_offset = 0; 405 mh->u.raw_video.field_gamma = 1.0; 406 mh->u.raw_video.field_sequence = 0; 407 mh->u.raw_video.field_number = 0; 408 mh->u.raw_video.pulldown_number = 0; 409 mh->u.raw_video.first_active_line = 1; 410 mh->u.raw_video.line_count = 0; 411 412 #if DEBUG 413 int32 chunk = 0; 414 #endif 415 416 status_t ret = B_OK; 417 418 do { 419 if (fLeftInChunkBuffer <= MIN_USEFUL_BYTES) { 420 uint8* leftOverBuffer = NULL; 421 size_t leftOverBufferSize = 0; 422 if (fLeftInChunkBuffer > 0) { 423 // we need to wrap the chunk buffer 424 // create a temporary buffer to hold the remaining data 425 leftOverBufferSize = fLeftInChunkBuffer; 426 leftOverBuffer = new (nothrow) uint8[leftOverBufferSize]; 427 if (!leftOverBuffer) 428 ret = B_NO_MEMORY; 429 else { 430 memcpy(leftOverBuffer, fChunkBufferHandle, 431 leftOverBufferSize); 432 } 433 } 434 // we don't need the previous wrapped buffer anymore in 435 // case we had it 436 delete[] fWrappedChunkBuffer; 437 fWrappedChunkBuffer = NULL; 438 439 // read new data 440 if (ret >= B_OK) 441 ret = GetNextChunk(&fChunkBuffer, &fChunkBufferSize, mh); 442 if (ret >= B_OK) { 443 if (leftOverBuffer) { 444 fWrappedChunkBuffer = new (nothrow) uint8[fChunkBufferSize 445 + leftOverBufferSize]; 446 if (!fWrappedChunkBuffer) 447 ret = B_NO_MEMORY; 448 else { 449 // copy the left over buffer to the beginning of the 450 // wrapped chunk buffer 451 memcpy(fWrappedChunkBuffer, leftOverBuffer, 452 leftOverBufferSize); 453 // copy the new chunk buffer after that 454 memcpy(fWrappedChunkBuffer + leftOverBufferSize, 455 fChunkBuffer, fChunkBufferSize); 456 457 fChunkBufferSize += leftOverBufferSize; 458 fLeftInChunkBuffer = fChunkBufferSize; 459 fChunkBufferHandle = (const char*)fWrappedChunkBuffer; 460 } 461 } else { 462 fLeftInChunkBuffer = fChunkBufferSize; 463 fChunkBufferHandle = (const char*)fChunkBuffer; 464 } 465 } 466 if (ret < B_OK) { 467 fChunkBufferSize = 0; 468 fChunkBuffer = NULL; 469 fChunkBufferHandle = NULL; 470 } 471 delete[] leftOverBuffer; 472 } 473 474 // Check if there is a negative number of useful bytes left in buffer 475 // This means we went too far 476 if (!fChunkBufferHandle || fLeftInChunkBuffer < 0) { 477 break; 478 } 479 480 xvid_dec_stats_t xvidDecoderStats; 481 482 // This loop is needed to handle VOL/NVOP reading 483 do { 484 // Decode frame 485 int usedBytes = _XvidDecode((uchar*)fChunkBufferHandle, 486 (uchar*)outBuffer, fLeftInChunkBuffer, &xvidDecoderStats, 487 hurryUp); 488 489 // Resize image buffer if needed 490 if (xvidDecoderStats.type == XVID_TYPE_VOL) { 491 492 // Check if old buffer is smaller 493 if ((int)(fOutputVideoFormat.display.line_width 494 * fOutputVideoFormat.display.line_count) 495 < xvidDecoderStats.data.vol.width 496 * xvidDecoderStats.data.vol.height) { 497 498 fprintf(stderr, "XvidDecoder::Decode() - image size " 499 "changed: %dx%d\n", 500 xvidDecoderStats.data.vol.width, 501 xvidDecoderStats.data.vol.height); 502 503 return B_ERROR; 504 } 505 } 506 507 // Update buffer pointers 508 if (usedBytes > 0) { 509 fChunkBufferHandle += usedBytes; 510 fLeftInChunkBuffer -= usedBytes; 511 } 512 513// PRINT((%p->"XvidDecoder::Decode() - chunk %d: %d bytes consumed, " 514// "%d bytes in buffer\n", this, chunk++, usedBytes, 515// fLeftInChunkBuffer)); 516 517 } while (xvidDecoderStats.type <= 0 518 && fLeftInChunkBuffer > MIN_USEFUL_BYTES); 519 520 if (xvidDecoderStats.type > XVID_TYPE_NOTHING) { 521 // got a full frame 522 mh->size_used = fOutputVideoFormat.display.line_count 523 * fOutputVideoFormat.display.bytes_per_row; 524 break; 525 } 526 527 } while (fLeftInChunkBuffer > MIN_USEFUL_BYTES || ret >= B_OK); 528 529 if (ret != B_OK) { 530 PRINT(("%p->XvidDecoder::Decode() - error: %s\n", this, 531 strerror(ret))); 532 return ret; 533 } 534 535 mh->type = B_MEDIA_RAW_VIDEO; 536 mh->start_time = (bigtime_t) (1000000.0 * fFrame 537 / fOutputVideoFormat.field_rate); 538 mh->u.raw_video.field_sequence = fFrame; 539 mh->u.raw_video.first_active_line = 1; 540 mh->u.raw_video.line_count = fOutputVideoFormat.display.line_count; 541 542 *outFrameCount = 1; 543 544 fFrame++; 545 546 PRINT(("%p->XvidDecoder::Decode() - start_time=%02d:%02d.%02d " 547 "field_sequence=%u\n", this, 548 int((mh->start_time / 60000000) % 60), 549 int((mh->start_time / 1000000) % 60), 550 int((mh->start_time / 10000) % 100), 551 mh->u.raw_video.field_sequence)); 552 553//#if DEBUG 554// print_media_header(mh); 555// print_media_decode_info(info); 556//#endif 557 558 return B_OK; 559} 560 561 562status_t 563XvidDecoder::SeekedTo(int64 frame, bigtime_t time) 564{ 565 PRINT(("%p->XvidDecoder::SeekedTo(frame=%lld, time=%lld)\n", 566 this, frame, time)); 567 568 fFrame = frame; 569 570 fChunkBuffer = NULL; 571 fChunkBufferHandle = NULL; 572 fChunkBufferSize = 0; 573 fLeftInChunkBuffer = 0; 574 575 // this will cause the xvid core to discard any cached stuff 576 fDiscontinuity = true; 577 578 return B_OK; 579} 580 581 582// #pragma mark - 583 584 585static bool 586init_xvid(bool useAssembler, int debugLevel) 587{ 588 // XviD core initialization 589 xvid_gbl_init_t xvidGlobalInit; 590 591 // reset the structure with zeros 592 memset(&xvidGlobalInit, 0, sizeof(xvid_gbl_init_t)); 593 594 // version 595 xvidGlobalInit.version = XVID_VERSION; 596 597 // assembly usage setting 598 if (useAssembler) 599 xvidGlobalInit.cpu_flags = 0; 600 else 601 xvidGlobalInit.cpu_flags = XVID_CPU_FORCE; 602 603 // debug level 604 xvidGlobalInit.debug = debugLevel; 605 606 xvid_global(NULL, 0, &xvidGlobalInit, NULL); 607 608 return true; 609} 610 611 612static bool sXvidInitialized = init_xvid(true, 0); 613 614 615// _XvidInit 616int 617XvidDecoder::_XvidInit() 618{ 619 if (fXvidDecoderHandle != NULL) 620 return 0; 621 622 // XviD decoder initialization 623 xvid_dec_create_t xvidDecoderCreate; 624 625 // reset the structure with zeros 626 memset(&xvidDecoderCreate, 0, sizeof(xvid_dec_create_t)); 627 628 // version 629 xvidDecoderCreate.version = XVID_VERSION; 630 631 // bitmap dimensions -- xvidcore will resize when needed 632 xvidDecoderCreate.width = 0; 633 xvidDecoderCreate.height = 0; 634 635 int ret = xvid_decore(NULL, XVID_DEC_CREATE, &xvidDecoderCreate, NULL); 636 637 if (ret == 0) 638 fXvidDecoderHandle = xvidDecoderCreate.handle; 639 640 return ret; 641} 642 643// _XvidUninit 644int 645XvidDecoder::_XvidUninit() 646{ 647 if (fXvidDecoderHandle == NULL) 648 return 0; 649 650 int ret = xvid_decore(fXvidDecoderHandle, XVID_DEC_DESTROY, NULL, NULL); 651 if (ret == 0) { 652 fXvidDecoderHandle = NULL; 653 fXvidColorspace = 0; 654 } 655 return ret; 656} 657 658// handle_fp_exeption 659static void 660handle_fp_exeption(int sig, void* opaque) 661{ 662 printf("_XvidDecode(): WARNING: Xvid decoder raised SIGFPE exception.\n"); 663 664// TODO: enable when fenv.h is available 665// feclearexcept(FE_ALL_EXCEPT); 666 667 //jump back before xvid_decore() and take the other branch 668 siglongjmp((sigjmp_buf)opaque, 1); 669} 670 671// _XvidDecode 672int 673XvidDecoder::_XvidDecode(uchar *inStream, uchar *outStream, int inStreamSize, 674 xvid_dec_stats_t* xvidDecoderStats, bool hurryUp) 675{ 676 PRINT(("%p->XvidDecoder::_XvidDecode(%p, %p, %d)\n", this, inStream, 677 outStream, inStreamSize)); 678 679 if (inStream == NULL || inStreamSize == 0) 680 return -1; 681 682 xvid_dec_frame_t xvid_dec_frame; 683 684 // reset all structures 685 memset(&xvid_dec_frame, 0, sizeof(xvid_dec_frame_t)); 686 memset(xvidDecoderStats, 0, sizeof(xvid_dec_stats_t)); 687 688 // set version 689 xvid_dec_frame.version = XVID_VERSION; 690 xvidDecoderStats->version = XVID_VERSION; 691 692 // no general flags to set 693 xvid_dec_frame.general = 0; //XVID_DEBLOCKY | XVID_DEBLOCKUV; 694 if (hurryUp) 695 xvid_dec_frame.general |= XVID_LOWDELAY; 696 if (fDiscontinuity) { 697 xvid_dec_frame.general |= XVID_DISCONTINUITY; 698 fDiscontinuity = false; 699 } 700 701 // input stream 702 xvid_dec_frame.bitstream = inStream; 703 xvid_dec_frame.length = inStreamSize; 704 705 // output frame structure 706 xvid_dec_frame.output.plane[0] = outStream; 707 xvid_dec_frame.output.stride[0] = outStream ? 708 fOutputVideoFormat.display.bytes_per_row : 0; 709 xvid_dec_frame.output.csp = fXvidColorspace; 710 711 // prepare for possible floating point exception 712 sigjmp_buf preDecoreEnv; 713 714 struct sigaction action; 715 struct sigaction oldAction; 716 memset(&action, 0, sizeof(struct sigaction)); 717 action.sa_flags = 0; 718 action.sa_handler = (__signal_func_ptr)handle_fp_exeption; 719 action.sa_userdata = preDecoreEnv; 720 721 if (sigaction(SIGFPE, &action, &oldAction) != 0) 722 return -1; 723 724 int usedBytes; 725 if (sigsetjmp(preDecoreEnv, 1) == 0) { 726 // decode 727 usedBytes = xvid_decore(fXvidDecoderHandle, XVID_DEC_DECODE, 728 &xvid_dec_frame, xvidDecoderStats); 729 } else { 730 // make sure the state changes before calling xvid_decore again 731 // or we'll cause the same exception 732 usedBytes = 1; 733 } 734 735 if (sigaction(SIGFPE, &oldAction, &action) != 0) 736 return -1; 737 738 return usedBytes; 739} 740 741// #pragma mark - 742 743 744status_t 745XvidPlugin::GetSupportedFormats(media_format** _mediaFormatArray, size_t *_count) 746{ 747 PRINT(("XvidDecoder::register_decoder()\n")); 748 749 static bool codecsRegistered = false; 750 if (codecsRegistered) 751 return B_OK; 752 codecsRegistered = true; 753 754 PRINT(("XvidDecoder: registering %d codecs\n", gSupportedCodecsCount)); 755 756 media_format_description descr[gSupportedCodecsCount]; 757 758 for (int i = 0; i < gSupportedCodecsCount; i++) { 759 descr[i].family = gCodecTable[i].family; 760 switch(descr[i].family) { 761 case B_AVI_FORMAT_FAMILY: 762 descr[i].u.avi.codec = gCodecTable[i].fourcc; 763 break; 764 case B_MPEG_FORMAT_FAMILY: 765 descr[i].u.mpeg.id = gCodecTable[i].fourcc; 766 break; 767 case B_QUICKTIME_FORMAT_FAMILY: 768 descr[i].u.quicktime.codec = gCodecTable[i].fourcc; 769 break; 770 default: 771 break; 772 } 773 } 774 775 BMediaFormats formats; 776 for (int i = 0; i < gSupportedCodecsCount; i++) { 777 media_format format; 778 format.type = B_MEDIA_ENCODED_VIDEO; 779 format.u.encoded_video = media_encoded_video_format::wildcard; 780 format.require_flags = 0; 781 format.deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 782 783 status_t err = formats.MakeFormatFor(&descr[i], 1, &format); 784 785 if (err < B_OK) { 786 fprintf(stderr, "XvidDecoder: BMediaFormats::MakeFormatFor: " 787 "error %s\n", strerror(err)); 788 continue; 789 } 790 791 gXvidFormats[i] = format; 792 } 793 794 *_mediaFormatArray = gXvidFormats; 795 *_count = gSupportedCodecsCount; 796 797 return B_OK; 798} 799 800 801Decoder* 802XvidPlugin::NewDecoder(uint index) 803{ 804 return new (nothrow) XvidDecoder(); 805} 806 807 808MediaPlugin *instantiate_plugin() 809{ 810 return new (nothrow) XvidPlugin; 811} 812 813 814