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