|
MythTV
0.26-pre
|
00001 /********** 00002 This library is free software; you can redistribute it and/or modify it under 00003 the terms of the GNU Lesser General Public License as published by the 00004 Free Software Foundation; either version 2.1 of the License, or (at your 00005 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) 00006 00007 This library is distributed in the hope that it will be useful, but WITHOUT 00008 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00009 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 00010 more details. 00011 00012 You should have received a copy of the GNU Lesser General Public License 00013 along with this library; if not, write to the Free Software Foundation, Inc., 00014 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00015 **********/ 00016 // "liveMedia" 00017 // Copyright (c) 1996-2005 Live Networks, Inc. All rights reserved. 00018 // A filter that breaks up an MPEG 1 or 2 video elementary stream into 00019 // frames for: Video_Sequence_Header, GOP_Header, Picture_Header 00020 // Implementation 00021 00022 #include "MPEG1or2VideoStreamFramer.hh" 00023 #include "MPEGVideoStreamParser.hh" 00024 #include <string.h> 00025 00027 00028 // An enum representing the current state of the parser: 00029 enum MPEGParseState { 00030 PARSING_VIDEO_SEQUENCE_HEADER, 00031 PARSING_VIDEO_SEQUENCE_HEADER_SEEN_CODE, 00032 PARSING_GOP_HEADER, 00033 PARSING_GOP_HEADER_SEEN_CODE, 00034 PARSING_PICTURE_HEADER, 00035 PARSING_SLICE 00036 }; 00037 00038 #define VSH_MAX_SIZE 1000 00039 00040 class MPEG1or2VideoStreamParser: public MPEGVideoStreamParser { 00041 public: 00042 MPEG1or2VideoStreamParser(MPEG1or2VideoStreamFramer* usingSource, 00043 FramedSource* inputSource, 00044 Boolean iFramesOnly, double vshPeriod); 00045 virtual ~MPEG1or2VideoStreamParser(); 00046 00047 private: // redefined virtual functions: 00048 virtual void flushInput(); 00049 virtual unsigned parse(); 00050 00051 private: 00052 void reset(); 00053 00054 MPEG1or2VideoStreamFramer* usingSource() { 00055 return (MPEG1or2VideoStreamFramer*)fUsingSource; 00056 } 00057 void setParseState(MPEGParseState parseState); 00058 00059 unsigned parseVideoSequenceHeader(Boolean haveSeenStartCode); 00060 unsigned parseGOPHeader(Boolean haveSeenStartCode); 00061 unsigned parsePictureHeader(); 00062 unsigned parseSlice(); 00063 00064 private: 00065 MPEGParseState fCurrentParseState; 00066 unsigned fPicturesSinceLastGOP; 00067 // can be used to compute timestamp for a video_sequence_header 00068 unsigned short fCurPicTemporalReference; 00069 // used to compute slice timestamp 00070 unsigned char fCurrentSliceNumber; // set when parsing a slice 00071 00072 // A saved copy of the most recently seen 'video_sequence_header', 00073 // in case we need to insert it into the stream periodically: 00074 unsigned char fSavedVSHBuffer[VSH_MAX_SIZE]; 00075 unsigned fSavedVSHSize; 00076 double fSavedVSHTimestamp; 00077 double fVSHPeriod; 00078 Boolean fIFramesOnly, fSkippingCurrentPicture; 00079 00080 void saveCurrentVSH(); 00081 Boolean needToUseSavedVSH(); 00082 unsigned useSavedVSH(); // returns the size of the saved VSH 00083 }; 00084 00085 00087 00088 MPEG1or2VideoStreamFramer::MPEG1or2VideoStreamFramer(UsageEnvironment& env, 00089 FramedSource* inputSource, 00090 Boolean iFramesOnly, 00091 double vshPeriod, 00092 Boolean createParser) 00093 : MPEGVideoStreamFramer(env, inputSource) { 00094 fParser = createParser 00095 ? new MPEG1or2VideoStreamParser(this, inputSource, 00096 iFramesOnly, vshPeriod) 00097 : NULL; 00098 } 00099 00100 MPEG1or2VideoStreamFramer::~MPEG1or2VideoStreamFramer() { 00101 } 00102 00103 MPEG1or2VideoStreamFramer* 00104 MPEG1or2VideoStreamFramer::createNew(UsageEnvironment& env, 00105 FramedSource* inputSource, 00106 Boolean iFramesOnly, 00107 double vshPeriod) { 00108 // Need to add source type checking here??? ##### 00109 return new MPEG1or2VideoStreamFramer(env, inputSource, iFramesOnly, vshPeriod); 00110 } 00111 00112 double MPEG1or2VideoStreamFramer::getCurrentPTS() const { 00113 return fPresentationTime.tv_sec + fPresentationTime.tv_usec/1000000.0; 00114 } 00115 00116 Boolean MPEG1or2VideoStreamFramer::isMPEG1or2VideoStreamFramer() const { 00117 return True; 00118 } 00119 00121 00122 MPEG1or2VideoStreamParser 00123 ::MPEG1or2VideoStreamParser(MPEG1or2VideoStreamFramer* usingSource, 00124 FramedSource* inputSource, 00125 Boolean iFramesOnly, double vshPeriod) 00126 : MPEGVideoStreamParser(usingSource, inputSource), 00127 fCurrentParseState(PARSING_VIDEO_SEQUENCE_HEADER), 00128 fVSHPeriod(vshPeriod), fIFramesOnly(iFramesOnly) { 00129 reset(); 00130 } 00131 00132 MPEG1or2VideoStreamParser::~MPEG1or2VideoStreamParser() { 00133 } 00134 00135 void MPEG1or2VideoStreamParser::setParseState(MPEGParseState parseState) { 00136 fCurrentParseState = parseState; 00137 MPEGVideoStreamParser::setParseState(); 00138 } 00139 00140 void MPEG1or2VideoStreamParser::reset() { 00141 fPicturesSinceLastGOP = 0; 00142 fCurPicTemporalReference = 0; 00143 fCurrentSliceNumber = 0; 00144 fSavedVSHSize = 0; 00145 fSkippingCurrentPicture = False; 00146 } 00147 00148 void MPEG1or2VideoStreamParser::flushInput() { 00149 reset(); 00150 StreamParser::flushInput(); 00151 if (fCurrentParseState != PARSING_VIDEO_SEQUENCE_HEADER) { 00152 setParseState(PARSING_GOP_HEADER); // start from the next GOP 00153 } 00154 } 00155 00156 unsigned MPEG1or2VideoStreamParser::parse() { 00157 try { 00158 switch (fCurrentParseState) { 00159 case PARSING_VIDEO_SEQUENCE_HEADER: { 00160 return parseVideoSequenceHeader(False); 00161 } 00162 case PARSING_VIDEO_SEQUENCE_HEADER_SEEN_CODE: { 00163 return parseVideoSequenceHeader(True); 00164 } 00165 case PARSING_GOP_HEADER: { 00166 return parseGOPHeader(False); 00167 } 00168 case PARSING_GOP_HEADER_SEEN_CODE: { 00169 return parseGOPHeader(True); 00170 } 00171 case PARSING_PICTURE_HEADER: { 00172 return parsePictureHeader(); 00173 } 00174 case PARSING_SLICE: { 00175 return parseSlice(); 00176 } 00177 default: { 00178 return 0; // shouldn't happen 00179 } 00180 } 00181 } catch (int /*e*/) { 00182 #ifdef DEBUG 00183 fprintf(stderr, "MPEG1or2VideoStreamParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n"); 00184 #endif 00185 return 0; // the parsing got interrupted 00186 } 00187 } 00188 00189 void MPEG1or2VideoStreamParser::saveCurrentVSH() { 00190 unsigned frameSize = curFrameSize(); 00191 if (frameSize > sizeof fSavedVSHBuffer) return; // too big to save 00192 00193 memmove(fSavedVSHBuffer, fStartOfFrame, frameSize); 00194 fSavedVSHSize = frameSize; 00195 fSavedVSHTimestamp = usingSource()->getCurrentPTS(); 00196 } 00197 00198 Boolean MPEG1or2VideoStreamParser::needToUseSavedVSH() { 00199 return usingSource()->getCurrentPTS() > fSavedVSHTimestamp+fVSHPeriod 00200 && fSavedVSHSize > 0; 00201 } 00202 00203 unsigned MPEG1or2VideoStreamParser::useSavedVSH() { 00204 unsigned bytesToUse = fSavedVSHSize; 00205 unsigned maxBytesToUse = fLimit - fStartOfFrame; 00206 if (bytesToUse > maxBytesToUse) bytesToUse = maxBytesToUse; 00207 00208 memmove(fStartOfFrame, fSavedVSHBuffer, bytesToUse); 00209 00210 // Also reset the saved timestamp: 00211 fSavedVSHTimestamp = usingSource()->getCurrentPTS(); 00212 00213 #ifdef DEBUG 00214 fprintf(stderr, "used saved video_sequence_header (%d bytes)\n", bytesToUse); 00215 #endif 00216 return bytesToUse; 00217 } 00218 00219 #define VIDEO_SEQUENCE_HEADER_START_CODE 0x000001B3 00220 #define GROUP_START_CODE 0x000001B8 00221 #define PICTURE_START_CODE 0x00000100 00222 #define SEQUENCE_END_CODE 0x000001B7 00223 00224 static double const frameRateFromCode[] = { 00225 0.0, // forbidden 00226 24000/1001.0, // approx 23.976 00227 24.0, 00228 25.0, 00229 30000/1001.0, // approx 29.97 00230 30.0, 00231 50.0, 00232 60000/1001.0, // approx 59.94 00233 60.0, 00234 0.0, // reserved 00235 0.0, // reserved 00236 0.0, // reserved 00237 0.0, // reserved 00238 0.0, // reserved 00239 0.0, // reserved 00240 0.0 // reserved 00241 }; 00242 00243 unsigned MPEG1or2VideoStreamParser 00244 ::parseVideoSequenceHeader(Boolean haveSeenStartCode) { 00245 #ifdef DEBUG 00246 fprintf(stderr, "parsing video sequence header\n"); 00247 #endif 00248 unsigned first4Bytes; 00249 if (!haveSeenStartCode) { 00250 while ((first4Bytes = test4Bytes()) != VIDEO_SEQUENCE_HEADER_START_CODE) { 00251 #ifdef DEBUG 00252 fprintf(stderr, "ignoring non video sequence header: 0x%08x\n", first4Bytes); 00253 #endif 00254 get1Byte(); setParseState(PARSING_VIDEO_SEQUENCE_HEADER); 00255 // ensures we progress over bad data 00256 } 00257 first4Bytes = get4Bytes(); 00258 } else { 00259 // We've already seen the start code 00260 first4Bytes = VIDEO_SEQUENCE_HEADER_START_CODE; 00261 } 00262 save4Bytes(first4Bytes); 00263 00264 // Next, extract the size and rate parameters from the next 8 bytes 00265 unsigned paramWord1 = get4Bytes(); 00266 save4Bytes(paramWord1); 00267 unsigned next4Bytes = get4Bytes(); 00268 #ifdef DEBUG 00269 unsigned short horizontal_size_value = (paramWord1&0xFFF00000)>>(32-12); 00270 unsigned short vertical_size_value = (paramWord1&0x000FFF00)>>8; 00271 unsigned char aspect_ratio_information = (paramWord1&0x000000F0)>>4; 00272 #endif 00273 unsigned char frame_rate_code = (paramWord1&0x0000000F); 00274 usingSource()->fFrameRate = frameRateFromCode[frame_rate_code]; 00275 #ifdef DEBUG 00276 unsigned bit_rate_value = (next4Bytes&0xFFFFC000)>>(32-18); 00277 unsigned vbv_buffer_size_value = (next4Bytes&0x00001FF8)>>3; 00278 fprintf(stderr, "horizontal_size_value: %d, vertical_size_value: %d, aspect_ratio_information: %d, frame_rate_code: %d (=>%f fps), bit_rate_value: %d (=>%d bps), vbv_buffer_size_value: %d\n", horizontal_size_value, vertical_size_value, aspect_ratio_information, frame_rate_code, usingSource()->fFrameRate, bit_rate_value, bit_rate_value*400, vbv_buffer_size_value); 00279 #endif 00280 00281 // Now, copy all bytes that we see, up until we reach a GROUP_START_CODE 00282 // or a PICTURE_START_CODE: 00283 do { 00284 saveToNextCode(next4Bytes); 00285 } while (next4Bytes != GROUP_START_CODE && next4Bytes != PICTURE_START_CODE); 00286 00287 setParseState((next4Bytes == GROUP_START_CODE) 00288 ? PARSING_GOP_HEADER_SEEN_CODE : PARSING_PICTURE_HEADER); 00289 00290 // Compute this frame's timestamp by noting how many pictures we've seen 00291 // since the last GOP header: 00292 usingSource()->computePresentationTime(fPicturesSinceLastGOP); 00293 00294 // Save this video_sequence_header, in case we need to insert a copy 00295 // into the stream later: 00296 saveCurrentVSH(); 00297 00298 return curFrameSize(); 00299 } 00300 00301 unsigned MPEG1or2VideoStreamParser::parseGOPHeader(Boolean haveSeenStartCode) { 00302 // First check whether we should insert a previously-saved 00303 // 'video_sequence_header' here: 00304 if (needToUseSavedVSH()) return useSavedVSH(); 00305 00306 #ifdef DEBUG 00307 fprintf(stderr, "parsing GOP header\n"); 00308 #endif 00309 unsigned first4Bytes; 00310 if (!haveSeenStartCode) { 00311 while ((first4Bytes = test4Bytes()) != GROUP_START_CODE) { 00312 #ifdef DEBUG 00313 fprintf(stderr, "ignoring non GOP start code: 0x%08x\n", first4Bytes); 00314 #endif 00315 get1Byte(); setParseState(PARSING_GOP_HEADER); 00316 // ensures we progress over bad data 00317 } 00318 first4Bytes = get4Bytes(); 00319 } else { 00320 // We've already seen the GROUP_START_CODE 00321 first4Bytes = GROUP_START_CODE; 00322 } 00323 save4Bytes(first4Bytes); 00324 00325 // Next, extract the (25-bit) time code from the next 4 bytes: 00326 unsigned next4Bytes = get4Bytes(); 00327 unsigned time_code = (next4Bytes&0xFFFFFF80)>>(32-25); 00328 #if defined(DEBUG) || defined(DEBUG_TIMESTAMPS) 00329 Boolean drop_frame_flag = (time_code&0x01000000) != 0; 00330 #endif 00331 unsigned time_code_hours = (time_code&0x00F80000)>>19; 00332 unsigned time_code_minutes = (time_code&0x0007E000)>>13; 00333 unsigned time_code_seconds = (time_code&0x00000FC0)>>6; 00334 unsigned time_code_pictures = (time_code&0x0000003F); 00335 #if defined(DEBUG) || defined(DEBUG_TIMESTAMPS) 00336 fprintf(stderr, "time_code: 0x%07x, drop_frame %d, hours %d, minutes %d, seconds %d, pictures %d\n", time_code, drop_frame_flag, time_code_hours, time_code_minutes, time_code_seconds, time_code_pictures); 00337 #endif 00338 #ifdef DEBUG 00339 Boolean closed_gop = (next4Bytes&0x00000040) != 0; 00340 Boolean broken_link = (next4Bytes&0x00000020) != 0; 00341 fprintf(stderr, "closed_gop: %d, broken_link: %d\n", closed_gop, broken_link); 00342 #endif 00343 00344 // Now, copy all bytes that we see, up until we reach a PICTURE_START_CODE: 00345 do { 00346 saveToNextCode(next4Bytes); 00347 } while (next4Bytes != PICTURE_START_CODE); 00348 00349 // Record the time code: 00350 usingSource()->setTimeCode(time_code_hours, time_code_minutes, 00351 time_code_seconds, time_code_pictures, 00352 fPicturesSinceLastGOP); 00353 00354 fPicturesSinceLastGOP = 0; 00355 00356 // Compute this frame's timestamp: 00357 usingSource()->computePresentationTime(0); 00358 00359 setParseState(PARSING_PICTURE_HEADER); 00360 00361 return curFrameSize(); 00362 } 00363 00364 inline Boolean isSliceStartCode(unsigned fourBytes) { 00365 if ((fourBytes&0xFFFFFF00) != 0x00000100) return False; 00366 00367 unsigned char lastByte = fourBytes&0xFF; 00368 return lastByte <= 0xAF && lastByte >= 1; 00369 } 00370 00371 unsigned MPEG1or2VideoStreamParser::parsePictureHeader() { 00372 #ifdef DEBUG 00373 fprintf(stderr, "parsing picture header\n"); 00374 #endif 00375 // Note that we've already read the PICTURE_START_CODE 00376 // Next, extract the temporal reference from the next 4 bytes: 00377 unsigned next4Bytes = get4Bytes(); 00378 unsigned short temporal_reference = (next4Bytes&0xFFC00000)>>(32-10); 00379 unsigned char picture_coding_type = (next4Bytes&0x00380000)>>19; 00380 #ifdef DEBUG 00381 unsigned short vbv_delay = (next4Bytes&0x0007FFF8)>>3; 00382 fprintf(stderr, "temporal_reference: %d, picture_coding_type: %d, vbv_delay: %d\n", temporal_reference, picture_coding_type, vbv_delay); 00383 #endif 00384 00385 fSkippingCurrentPicture = fIFramesOnly && picture_coding_type != 1; 00386 if (fSkippingCurrentPicture) { 00387 // Skip all bytes that we see, up until we reach a slice_start_code: 00388 do { 00389 skipToNextCode(next4Bytes); 00390 } while (!isSliceStartCode(next4Bytes)); 00391 } else { 00392 // Save the PICTURE_START_CODE that we've already read: 00393 save4Bytes(PICTURE_START_CODE); 00394 00395 // Copy all bytes that we see, up until we reach a slice_start_code: 00396 do { 00397 saveToNextCode(next4Bytes); 00398 } while (!isSliceStartCode(next4Bytes)); 00399 } 00400 00401 setParseState(PARSING_SLICE); 00402 00403 fCurrentSliceNumber = next4Bytes&0xFF; 00404 00405 // Record the temporal reference: 00406 fCurPicTemporalReference = temporal_reference; 00407 00408 // Compute this frame's timestamp: 00409 usingSource()->computePresentationTime(fCurPicTemporalReference); 00410 00411 if (fSkippingCurrentPicture) { 00412 return parse(); // try again, until we get a non-skipped frame 00413 } else { 00414 return curFrameSize(); 00415 } 00416 } 00417 00418 unsigned MPEG1or2VideoStreamParser::parseSlice() { 00419 // Note that we've already read the slice_start_code: 00420 unsigned next4Bytes = PICTURE_START_CODE|fCurrentSliceNumber; 00421 #ifdef DEBUG_SLICE 00422 fprintf(stderr, "parsing slice: 0x%08x\n", next4Bytes); 00423 #endif 00424 00425 if (fSkippingCurrentPicture) { 00426 // Skip all bytes that we see, up until we reach a code of some sort: 00427 skipToNextCode(next4Bytes); 00428 } else { 00429 // Copy all bytes that we see, up until we reach a code of some sort: 00430 saveToNextCode(next4Bytes); 00431 } 00432 00433 // The next thing to parse depends on the code that we just saw: 00434 if (isSliceStartCode(next4Bytes)) { // common case 00435 setParseState(PARSING_SLICE); 00436 fCurrentSliceNumber = next4Bytes&0xFF; 00437 } else { 00438 // Because we don't see any more slices, we are assumed to have ended 00439 // the current picture: 00440 ++fPicturesSinceLastGOP; 00441 ++usingSource()->fPictureCount; 00442 usingSource()->fPictureEndMarker = True; // HACK ##### 00443 00444 switch (next4Bytes) { 00445 case SEQUENCE_END_CODE: { 00446 setParseState(PARSING_VIDEO_SEQUENCE_HEADER); 00447 break; 00448 } 00449 case VIDEO_SEQUENCE_HEADER_START_CODE: { 00450 setParseState(PARSING_VIDEO_SEQUENCE_HEADER_SEEN_CODE); 00451 break; 00452 } 00453 case GROUP_START_CODE: { 00454 setParseState(PARSING_GOP_HEADER_SEEN_CODE); 00455 break; 00456 } 00457 case PICTURE_START_CODE: { 00458 setParseState(PARSING_PICTURE_HEADER); 00459 break; 00460 } 00461 default: { 00462 usingSource()->envir() << "MPEG1or2VideoStreamParser::parseSlice(): Saw unexpected code " 00463 << (void*)next4Bytes << "\n"; 00464 setParseState(PARSING_SLICE); // the safest way to recover... 00465 break; 00466 } 00467 } 00468 } 00469 00470 // Compute this frame's timestamp: 00471 usingSource()->computePresentationTime(fCurPicTemporalReference); 00472 00473 if (fSkippingCurrentPicture) { 00474 return parse(); // try again, until we get a non-skipped frame 00475 } else { 00476 return curFrameSize(); 00477 } 00478 }
1.7.6.1