00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "MPEG1or2VideoStreamFramer.hh"
00023 #include "MPEGVideoStreamParser.hh"
00024 #include <string.h>
00025
00027
00028
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:
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
00068 unsigned short fCurPicTemporalReference;
00069
00070 unsigned char fCurrentSliceNumber;
00071
00072
00073
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();
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
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);
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;
00179 }
00180 }
00181 } catch (int ) {
00182 #ifdef DEBUG
00183 fprintf(stderr, "MPEG1or2VideoStreamParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n");
00184 #endif
00185 return 0;
00186 }
00187 }
00188
00189 void MPEG1or2VideoStreamParser::saveCurrentVSH() {
00190 unsigned frameSize = curFrameSize();
00191 if (frameSize > sizeof fSavedVSHBuffer) return;
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
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,
00226 24000/1001.0,
00227 24.0,
00228 25.0,
00229 30000/1001.0,
00230 30.0,
00231 50.0,
00232 60000/1001.0,
00233 60.0,
00234 0.0,
00235 0.0,
00236 0.0,
00237 0.0,
00238 0.0,
00239 0.0,
00240 0.0
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
00256 }
00257 first4Bytes = get4Bytes();
00258 } else {
00259
00260 first4Bytes = VIDEO_SEQUENCE_HEADER_START_CODE;
00261 }
00262 save4Bytes(first4Bytes);
00263
00264
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
00282
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
00291
00292 usingSource()->computePresentationTime(fPicturesSinceLastGOP);
00293
00294
00295
00296 saveCurrentVSH();
00297
00298 return curFrameSize();
00299 }
00300
00301 unsigned MPEG1or2VideoStreamParser::parseGOPHeader(Boolean haveSeenStartCode) {
00302
00303
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
00317 }
00318 first4Bytes = get4Bytes();
00319 } else {
00320
00321 first4Bytes = GROUP_START_CODE;
00322 }
00323 save4Bytes(first4Bytes);
00324
00325
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
00345 do {
00346 saveToNextCode(next4Bytes);
00347 } while (next4Bytes != PICTURE_START_CODE);
00348
00349
00350 usingSource()->setTimeCode(time_code_hours, time_code_minutes,
00351 time_code_seconds, time_code_pictures,
00352 fPicturesSinceLastGOP);
00353
00354 fPicturesSinceLastGOP = 0;
00355
00356
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
00376
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
00388 do {
00389 skipToNextCode(next4Bytes);
00390 } while (!isSliceStartCode(next4Bytes));
00391 } else {
00392
00393 save4Bytes(PICTURE_START_CODE);
00394
00395
00396 do {
00397 saveToNextCode(next4Bytes);
00398 } while (!isSliceStartCode(next4Bytes));
00399 }
00400
00401 setParseState(PARSING_SLICE);
00402
00403 fCurrentSliceNumber = next4Bytes&0xFF;
00404
00405
00406 fCurPicTemporalReference = temporal_reference;
00407
00408
00409 usingSource()->computePresentationTime(fCurPicTemporalReference);
00410
00411 if (fSkippingCurrentPicture) {
00412 return parse();
00413 } else {
00414 return curFrameSize();
00415 }
00416 }
00417
00418 unsigned MPEG1or2VideoStreamParser::parseSlice() {
00419
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
00427 skipToNextCode(next4Bytes);
00428 } else {
00429
00430 saveToNextCode(next4Bytes);
00431 }
00432
00433
00434 if (isSliceStartCode(next4Bytes)) {
00435 setParseState(PARSING_SLICE);
00436 fCurrentSliceNumber = next4Bytes&0xFF;
00437 } else {
00438
00439
00440 ++fPicturesSinceLastGOP;
00441 ++usingSource()->fPictureCount;
00442 usingSource()->fPictureEndMarker = True;
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);
00465 break;
00466 }
00467 }
00468 }
00469
00470
00471 usingSource()->computePresentationTime(fCurPicTemporalReference);
00472
00473 if (fSkippingCurrentPicture) {
00474 return parse();
00475 } else {
00476 return curFrameSize();
00477 }
00478 }