00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <mxcpcFramewiseMxPEGDecoder.h>
00021 #include <mxcpcFramewiseMxPEGScanDecoder.h>
00022 #include <mxcpcStreamSource.h>
00023 #include <mxcpcMxPEGDecoderBackEnd.h>
00024 #include <mxcpc_exceptions.h>
00025 #include <mxcpc_namespace.h>
00026
00027 #include <exception>
00028 #include <cstdio>
00029 #include <cstring>
00030 #include <cstdlib>
00031 #include <typeinfo>
00032
00033
00034
00035 mxcpcFramewiseMxPEGDecoder
00036 ::mxcpcFramewiseMxPEGDecoder(mxcpcStreamSource *source,
00037 mxcpcMxPEGDecoderBackEnd *backend,
00038 mxcpcFramewiseMxPEGScanDecoder
00039 *scan_decoder)
00040 : mxcpcMxPEGDecoder(source, backend) {
00041
00042 char txt[100], txt2[200];
00043
00044 PrefetchBuffSize = 4 * 1024 * 1024;
00045 PrefetchedBytes = 0;
00046
00047 PrefetchBuffer = 0;
00048 try {
00049
00050 PrefetchBuffer = new unsigned char[PrefetchBuffSize];
00051
00052 } catch(std::exception &e) {
00053
00054 MXCPC_RETHROW_UNHANDLED_EXCEPTION(e);
00055
00056 delete[] PrefetchBuffer;
00057
00058 throw;
00059 }
00060
00061
00062
00063 State = AwaitSOI;
00064
00065 CurrentBytePtr = 0;
00066 BytesLeft = 0;
00067
00068 AwaitMarkerStage = 0;
00069
00070 ReadMarkerStage = 0;
00071 ReadMarkerFirstLenByte = 0;
00072 MarkerBytesNeeded = 0;
00073
00074 ScanStage = 0;
00075
00076 MarkerPayload = 0;
00077
00078 Width = Height = 0;
00079 ScanDecoder = scan_decoder;
00080 ScanDecoder->setBackEnd(backend);
00081
00082 std::strncpy(txt, ScanDecoder->getAccelerationTypeString(), 100);
00083 txt[99] = '\0';
00084 std::sprintf(txt2, "FramewiseMxPEGDecoder : acceleration method : %s",
00085 txt);
00086 mxcpc::sendStatusMsg(txt2);
00087 }
00088
00089
00090 mxcpcFramewiseMxPEGDecoder::~mxcpcFramewiseMxPEGDecoder() {
00091
00092 delete[] PrefetchBuffer;
00093 delete ScanDecoder;
00094 }
00095
00096
00097
00098 int mxcpcFramewiseMxPEGDecoder::decode(int num) {
00099
00100 int bytes_allowed;
00101 unsigned char *buff_ptr;
00102 int bytes_read, bytes_processed;
00103
00104
00105 bytes_allowed = PrefetchBuffSize - PrefetchedBytes;
00106 if(bytes_allowed > num) bytes_allowed = num;
00107 if(bytes_allowed < 1) {
00108 mxcpc::sendStatusMsg("!!! MxPEG decoder failure (prefetch buffer overflow) !!!", this);
00109 std::exit(666);
00110
00111 }
00112
00113 bytes_processed = 0;
00114 while(bytes_allowed > 0) {
00115
00116 buff_ptr = PrefetchBuffer + PrefetchedBytes;
00117 bytes_read = StreamSource->fetchBytes(buff_ptr, bytes_allowed);
00118 if(!bytes_read) break;
00119
00120 PrefetchedBytes += bytes_read;
00121
00122 feedBytes(buff_ptr, bytes_read);
00123
00124
00125 bytes_processed += bytes_read;
00126 bytes_allowed -= bytes_read;
00127 }
00128
00129 return(bytes_processed);
00130 }
00131
00132
00133 void mxcpcFramewiseMxPEGDecoder::feedBytes(unsigned char *buffer,
00134 int num) {
00135
00136 unsigned char marker_type;
00137 int width, height;
00138 bool need_to_copy_down;
00139
00140 if(num < 1) return;
00141
00142 CurrentBytePtr = buffer;
00143 BytesLeft = num;
00144 while(BytesLeft) {
00145
00146 need_to_copy_down = false;
00147
00148 switch(State) {
00149
00150
00151
00152 case AwaitSOI:
00153 if(!awaitMarker(&marker_type)) return;
00154 if(marker_type == 0xd8)
00155 State = AwaitAPP0;
00156 else
00157 State = No_Good_State;
00158 break;
00159
00160 case AwaitAPP0:
00161 if(!awaitMarker(&marker_type)) return;
00162 if(marker_type == 0xe0)
00163 State = APP0;
00164 else
00165 State = No_Good_State;
00166 break;
00167
00168 case APP0:
00169 if(!readMarkerPayload()) return;
00170 State = Determine_FingerPrint_Or_FrameHeader;
00171 break;
00172
00173 case Determine_FingerPrint_Or_FrameHeader:
00174 if(!awaitMarker(&marker_type)) return;
00175 if(marker_type == 0xfe) State = Determine_FingerPrint_Or_FrameHeader2;
00176 else State = No_Good_State;
00177 break;
00178
00179 case Determine_FingerPrint_Or_FrameHeader2:
00180 if(!readMarkerPayload()) return;
00181 if(!strncmp((char *)MarkerPayload, "#:M1IMG", 7))
00182 State = FingerPrint;
00183 else if(!strncmp((char *)MarkerPayload, "MXF", 3))
00184 State = FrameHeader;
00185 else
00186 State = No_Good_State;
00187 break;
00188
00189 case FingerPrint:
00190 State = AwaitFrameHeader;
00191 break;
00192
00193 case AwaitFrameHeader:
00194 if(!awaitMarker(&marker_type)) return;
00195 if(marker_type == 0xfe)
00196 State = AwaitFrameHeader2;
00197 else
00198 State = No_Good_State;
00199 break;
00200
00201 case AwaitFrameHeader2:
00202 if(!readMarkerPayload()) return;
00203 if(!strncmp((char *)MarkerPayload, "MXF", 3))
00204 State = FrameHeader;
00205 else
00206 State = No_Good_State;
00207 break;
00208
00209 case FrameHeader:
00210 State = BitMask_Or_Tables;
00211 break;
00212
00213 case BitMask_Or_Tables:
00214 if(!awaitMarker(&marker_type)) return;
00215 if(marker_type == 0xdb) {
00216 FrameDescriptor.TileBits = 0;
00217 State = QuantizationTable1;
00218 }
00219 else if(marker_type == 0xfe)
00220 State = BitMask;
00221 else
00222 State = No_Good_State;
00223 break;
00224
00225 case QuantizationTable1:
00226 if(!readMarkerPayload()) return;
00227 ScanDecoder->setYQuantizationTable(&MarkerPayload[1]);
00228 State = AwaitQuantizationTable2;
00229 break;
00230
00231 case AwaitQuantizationTable2:
00232 if(!awaitMarker(&marker_type)) return;
00233 if(marker_type == 0xdb)
00234 State = QuantizationTable2;
00235 else
00236 State = No_Good_State;
00237 break;
00238
00239 case QuantizationTable2:
00240 if(!readMarkerPayload()) return;
00241 ScanDecoder->setUVQuantizationTable(&MarkerPayload[1]);
00242 State = Huffman_Or_SOF;
00243 break;
00244
00245 case Huffman_Or_SOF:
00246 if(!awaitMarker(&marker_type)) return;
00247 if(marker_type == 0xc4)
00248 State = HuffmanTable;
00249 else if(marker_type == 0xc0)
00250 State = SOF;
00251 else
00252 State = No_Good_State;
00253 break;
00254
00255 case SOF:
00256 if(!readMarkerPayload()) return;
00257 width = (int)MarkerPayload[3]*256 + (int)MarkerPayload[4];
00258 height = (int)MarkerPayload[1]*256 + (int)MarkerPayload[2];
00259 FrameDescriptor.setResolution(width, height);
00260 State = Huffman_Or_Scan;
00261 break;
00262
00263 case HuffmanTable:
00264 if(!readMarkerPayload()) return;
00265 State = Huffman_Or_Scan;
00266 break;
00267
00268 case Huffman_Or_Scan:
00269 if(!awaitMarker(&marker_type)) return;
00270 if(marker_type == 0xda)
00271 State = Scan;
00272 else if(marker_type == 0xc4)
00273 State = HuffmanTable;
00274 else
00275 State = No_Good_State;
00276 break;
00277
00278 case Scan:
00279 if(!readMarkerPayload()) return;
00280 FrameDescriptor.ScanBytes = CurrentBytePtr;
00281 State = Scan2;
00282 break;
00283
00284 case Scan2:
00285 if(!doScan()) return;
00286 FrameDescriptor.ScanLength = CurrentBytePtr - FrameDescriptor.ScanBytes;
00287 State = Audio_Or_SOI;
00288 break;
00289
00290 case BitMask:
00291 if(!readMarkerPayload()) return;
00292 FrameDescriptor.TileBits = &MarkerPayload[12];
00293 State = Tables_Or_Scan;
00294 break;
00295
00296 case Tables_Or_Scan:
00297 if(!awaitMarker(&marker_type)) return;
00298 if(marker_type == 0xdb)
00299 State = QuantizationTable1;
00300 else if(marker_type == 0xda)
00301 State = Scan;
00302 else
00303 State = No_Good_State;
00304 break;
00305
00306 case Audio_Or_SOI:
00307 if(!awaitMarker(&marker_type)) return;
00308 if(marker_type == 0xed)
00309 State = Audio;
00310 else if(marker_type == 0xd8) {
00311 need_to_copy_down = true;
00312 State = AwaitAPP0;
00313 }
00314 else {
00315 need_to_copy_down = true;
00316 State = No_Good_State;
00317 }
00318 break;
00319
00320 case Audio:
00321 if(!readMarkerPayload()) return;
00322 need_to_copy_down = true;
00323 State = AwaitSOI;
00324 break;
00325
00326 case No_Good_State:
00327 mxcpc::sendStatusMsg("!!! MxPEG decoder failure (no_good_state) !!!", this);
00328 std::exit(666);
00329 break;
00330
00331 default:
00332 mxcpc::sendStatusMsg("!!! MxPEG decoder INTERNAL FAILURE !!!");
00333 std::exit(666);
00334 break;
00335 }
00336
00337 if(need_to_copy_down) {
00338
00339
00340
00341
00342 if( (FrameDescriptor.Width != Width)
00343 || (FrameDescriptor.Height != Height)) {
00344
00345 BackEnd->videoResolutionChanged(FrameDescriptor.Width,
00346 FrameDescriptor.Height);
00347 Width = FrameDescriptor.Width;
00348 Height = FrameDescriptor.Height;
00349 }
00350
00351 ScanDecoder->performScanSweep(&FrameDescriptor);
00352
00353 BackEnd->frameComplete();
00354
00355
00356 if(BytesLeft) {
00357 std::memmove(PrefetchBuffer, CurrentBytePtr, BytesLeft);
00358
00359 }
00360 CurrentBytePtr = PrefetchBuffer;
00361 PrefetchedBytes = BytesLeft;
00362
00363
00364
00365
00366 FrameDescriptor.reset(Width, Height);
00367 }
00368 }
00369 }
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380 bool mxcpcFramewiseMxPEGDecoder::awaitMarker(unsigned char *marker_type) {
00381
00382 if(AwaitMarkerStage == 0) {
00383
00384 while(BytesLeft) {
00385 if(*CurrentBytePtr == (unsigned char)0xff) {
00386 CurrentBytePtr++;
00387 BytesLeft--;
00388 if(BytesLeft) {
00389 *marker_type = *CurrentBytePtr;
00390 CurrentBytePtr++;
00391 BytesLeft--;
00392 return(true);
00393 }
00394 else {
00395
00396 AwaitMarkerStage = 1;
00397 return(false);
00398 }
00399 }
00400
00401 CurrentBytePtr++;
00402 BytesLeft--;
00403 }
00404 return(false);
00405 }
00406
00407 else {
00408 if(BytesLeft) {
00409 *marker_type = *CurrentBytePtr;
00410 CurrentBytePtr++;
00411 BytesLeft--;
00412 AwaitMarkerStage = 0;
00413 return(true);
00414 }
00415 else
00416 return(false);
00417 }
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427 bool mxcpcFramewiseMxPEGDecoder::readMarkerPayload(void) {
00428
00429 for(;;) {
00430
00431 if(ReadMarkerStage == 0) {
00432 if(!BytesLeft) return(false);
00433 else if(BytesLeft == 1) {
00434 ReadMarkerFirstLenByte = *CurrentBytePtr;
00435 CurrentBytePtr++;
00436 BytesLeft--;
00437 ReadMarkerStage = 1;
00438 return(false);
00439 }
00440 else {
00441 MarkerBytesNeeded = 256*(int)CurrentBytePtr[0]
00442 + (int)CurrentBytePtr[1]
00443 - 2;
00444 CurrentBytePtr += 2;
00445 BytesLeft -= 2;
00446 MarkerPayload = CurrentBytePtr;
00447 ReadMarkerStage = 2;
00448 continue;
00449 }
00450 }
00451
00452 else if(ReadMarkerStage == 1) {
00453 if(!BytesLeft) return(false);
00454 MarkerBytesNeeded = 256*(int)ReadMarkerFirstLenByte
00455 + (int)*CurrentBytePtr
00456 - 2;
00457 CurrentBytePtr++;
00458 BytesLeft--;
00459 MarkerPayload = CurrentBytePtr;
00460 ReadMarkerStage = 2;
00461 continue;
00462 }
00463
00464 else if(ReadMarkerStage == 2) {
00465
00466 if(!BytesLeft) return(false);
00467 if(BytesLeft >= MarkerBytesNeeded) {
00468 CurrentBytePtr += MarkerBytesNeeded;
00469 BytesLeft -= MarkerBytesNeeded;
00470 MarkerBytesNeeded = 0;
00471 ReadMarkerFirstLenByte = 0;
00472 ReadMarkerStage = 0;
00473 return(true);
00474 }
00475 else {
00476 MarkerBytesNeeded -= BytesLeft;
00477 CurrentBytePtr += BytesLeft;
00478 BytesLeft = 0;
00479 return(false);
00480 }
00481 }
00482 }
00483 }
00484
00485
00486
00487
00488
00489 bool mxcpcFramewiseMxPEGDecoder::doScan(void) {
00490
00491 label_doScan_begin:
00492
00493 if(ScanStage == 0) {
00494 while(BytesLeft) {
00495 if(*CurrentBytePtr == 0xff) {
00496 CurrentBytePtr++;
00497 BytesLeft--;
00498 if(!BytesLeft) {
00499 ScanStage = 1;
00500 return(false);
00501 }
00502 else {
00503 if(*CurrentBytePtr == 0x00) {
00504 CurrentBytePtr++;
00505 BytesLeft--;
00506 continue;
00507 }
00508 else if(*CurrentBytePtr == 0xd9) {
00509 CurrentBytePtr++;
00510 BytesLeft--;
00511 return(true);
00512 }
00513 else {
00514 mxcpc::sendStatusMsg("!!! MxPEG decoder failure "
00515 "(invalid scan termination) !!!");
00516 std::exit(666);
00517 }
00518 }
00519 }
00520 else {
00521 CurrentBytePtr++;
00522 BytesLeft--;
00523 }
00524 }
00525 return(false);
00526 }
00527
00528 else {
00529 if(!BytesLeft) return(false);
00530 if(*CurrentBytePtr == 0x00) {
00531 CurrentBytePtr++;
00532 BytesLeft--;
00533 ScanStage = 0;
00534 goto label_doScan_begin;
00535 }
00536 else if(*CurrentBytePtr == 0xd9) {
00537 CurrentBytePtr++;
00538 BytesLeft--;
00539 ScanStage = 0;
00540 return(true);
00541 }
00542 else {
00543 mxcpc::sendStatusMsg("!!! MxPEG decoder failure "
00544 "(invalid scan termination) !!!");
00545 std::exit(666);
00546 }
00547 }
00548 }
00549