| 1 | /********** | 
|---|
| 2 | This library is free software; you can redistribute it and/or modify it under | 
|---|
| 3 | the terms of the GNU Lesser General Public License as published by the | 
|---|
| 4 | Free Software Foundation; either version 3 of the License, or (at your | 
|---|
| 5 | option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) | 
|---|
| 6 |  | 
|---|
| 7 | This library is distributed in the hope that it will be useful, but WITHOUT | 
|---|
| 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | 
|---|
| 9 | FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for | 
|---|
| 10 | more details. | 
|---|
| 11 |  | 
|---|
| 12 | You should have received a copy of the GNU Lesser General Public License | 
|---|
| 13 | along with this library; if not, write to the Free Software Foundation, Inc., | 
|---|
| 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA | 
|---|
| 15 | **********/ | 
|---|
| 16 | // "liveMedia" | 
|---|
| 17 | // Copyright (c) 1996-2020 Live Networks, Inc.  All rights reserved. | 
|---|
| 18 | // A simplified version of "MPEG4VideoStreamFramer" that takes only complete, | 
|---|
| 19 | // discrete frames (rather than an arbitrary byte stream) as input. | 
|---|
| 20 | // This avoids the parsing and data copying overhead of the full | 
|---|
| 21 | // "MPEG4VideoStreamFramer". | 
|---|
| 22 | // Implementation | 
|---|
| 23 |  | 
|---|
| 24 | #include "MPEG4VideoStreamDiscreteFramer.hh" | 
|---|
| 25 |  | 
|---|
| 26 | MPEG4VideoStreamDiscreteFramer* | 
|---|
| 27 | MPEG4VideoStreamDiscreteFramer::createNew(UsageEnvironment& env, | 
|---|
| 28 | FramedSource* inputSource, Boolean leavePresentationTimesUnmodified) { | 
|---|
| 29 | // Need to add source type checking here???  ##### | 
|---|
| 30 | return new MPEG4VideoStreamDiscreteFramer(env, inputSource, leavePresentationTimesUnmodified); | 
|---|
| 31 | } | 
|---|
| 32 |  | 
|---|
| 33 | MPEG4VideoStreamDiscreteFramer | 
|---|
| 34 | ::MPEG4VideoStreamDiscreteFramer(UsageEnvironment& env, | 
|---|
| 35 | FramedSource* inputSource, Boolean leavePresentationTimesUnmodified) | 
|---|
| 36 | : MPEG4VideoStreamFramer(env, inputSource, False/*don't create a parser*/), | 
|---|
| 37 | fLeavePresentationTimesUnmodified(leavePresentationTimesUnmodified), vop_time_increment_resolution(0), fNumVTIRBits(0), | 
|---|
| 38 | fLastNonBFrameVop_time_increment(0) { | 
|---|
| 39 | fLastNonBFramePresentationTime.tv_sec = 0; | 
|---|
| 40 | fLastNonBFramePresentationTime.tv_usec = 0; | 
|---|
| 41 | } | 
|---|
| 42 |  | 
|---|
| 43 | MPEG4VideoStreamDiscreteFramer::~MPEG4VideoStreamDiscreteFramer() { | 
|---|
| 44 | } | 
|---|
| 45 |  | 
|---|
| 46 | void MPEG4VideoStreamDiscreteFramer::doGetNextFrame() { | 
|---|
| 47 | // Arrange to read data (which should be a complete MPEG-4 video frame) | 
|---|
| 48 | // from our data source, directly into the client's input buffer. | 
|---|
| 49 | // After reading this, we'll do some parsing on the frame. | 
|---|
| 50 | fInputSource->getNextFrame(fTo, fMaxSize, | 
|---|
| 51 | afterGettingFrame, this, | 
|---|
| 52 | FramedSource::handleClosure, this); | 
|---|
| 53 | } | 
|---|
| 54 |  | 
|---|
| 55 | void MPEG4VideoStreamDiscreteFramer | 
|---|
| 56 | ::afterGettingFrame(void* clientData, unsigned frameSize, | 
|---|
| 57 | unsigned numTruncatedBytes, | 
|---|
| 58 | struct timeval presentationTime, | 
|---|
| 59 | unsigned durationInMicroseconds) { | 
|---|
| 60 | MPEG4VideoStreamDiscreteFramer* source = (MPEG4VideoStreamDiscreteFramer*)clientData; | 
|---|
| 61 | source->afterGettingFrame1(frameSize, numTruncatedBytes, | 
|---|
| 62 | presentationTime, durationInMicroseconds); | 
|---|
| 63 | } | 
|---|
| 64 |  | 
|---|
| 65 | void MPEG4VideoStreamDiscreteFramer | 
|---|
| 66 | ::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes, | 
|---|
| 67 | struct timeval presentationTime, | 
|---|
| 68 | unsigned durationInMicroseconds) { | 
|---|
| 69 | // Check that the first 4 bytes are a system code: | 
|---|
| 70 | if (frameSize >= 4 && fTo[0] == 0 && fTo[1] == 0 && fTo[2] == 1) { | 
|---|
| 71 | fPictureEndMarker = True; // Assume that we have a complete 'picture' here | 
|---|
| 72 | unsigned i = 3; | 
|---|
| 73 | if (fTo[i] == 0xB0) { // VISUAL_OBJECT_SEQUENCE_START_CODE | 
|---|
| 74 | // The next byte is the "profile_and_level_indication": | 
|---|
| 75 | if (frameSize >= 5) fProfileAndLevelIndication = fTo[4]; | 
|---|
| 76 |  | 
|---|
| 77 | // The start of this frame - up to the first GROUP_VOP_START_CODE | 
|---|
| 78 | // or VOP_START_CODE - is stream configuration information.  Save this: | 
|---|
| 79 | for (i = 7; i < frameSize; ++i) { | 
|---|
| 80 | if ((fTo[i] == 0xB3 /*GROUP_VOP_START_CODE*/ || | 
|---|
| 81 | fTo[i] == 0xB6 /*VOP_START_CODE*/) | 
|---|
| 82 | && fTo[i-1] == 1 && fTo[i-2] == 0 && fTo[i-3] == 0) { | 
|---|
| 83 | break; // The configuration information ends here | 
|---|
| 84 | } | 
|---|
| 85 | } | 
|---|
| 86 | fNumConfigBytes = i < frameSize ? i-3 : frameSize; | 
|---|
| 87 | delete[] fConfigBytes; fConfigBytes = new unsigned char[fNumConfigBytes]; | 
|---|
| 88 | for (unsigned j = 0; j < fNumConfigBytes; ++j) fConfigBytes[j] = fTo[j]; | 
|---|
| 89 |  | 
|---|
| 90 | // This information (should) also contain a VOL header, which we need | 
|---|
| 91 | // to analyze, to get "vop_time_increment_resolution" (which we need | 
|---|
| 92 | // - along with "vop_time_increment" - in order to generate accurate | 
|---|
| 93 | // presentation times for "B" frames). | 
|---|
| 94 | analyzeVOLHeader(); | 
|---|
| 95 | } | 
|---|
| 96 |  | 
|---|
| 97 | if (i < frameSize) { | 
|---|
| 98 | u_int8_t nextCode = fTo[i]; | 
|---|
| 99 |  | 
|---|
| 100 | if (nextCode == 0xB3 /*GROUP_VOP_START_CODE*/) { | 
|---|
| 101 | // Skip to the following VOP_START_CODE (if any): | 
|---|
| 102 | for (i += 4; i < frameSize; ++i) { | 
|---|
| 103 | if (fTo[i] == 0xB6 /*VOP_START_CODE*/ | 
|---|
| 104 | && fTo[i-1] == 1 && fTo[i-2] == 0 && fTo[i-3] == 0) { | 
|---|
| 105 | nextCode = fTo[i]; | 
|---|
| 106 | break; | 
|---|
| 107 | } | 
|---|
| 108 | } | 
|---|
| 109 | } | 
|---|
| 110 |  | 
|---|
| 111 | if (nextCode == 0xB6 /*VOP_START_CODE*/ && i+5 < frameSize) { | 
|---|
| 112 | ++i; | 
|---|
| 113 |  | 
|---|
| 114 | // Get the "vop_coding_type" from the next byte: | 
|---|
| 115 | u_int8_t nextByte = fTo[i++]; | 
|---|
| 116 | u_int8_t vop_coding_type = nextByte>>6; | 
|---|
| 117 |  | 
|---|
| 118 | // Next, get the "modulo_time_base" by counting the '1' bits that | 
|---|
| 119 | // follow.  We look at the next 32-bits only. | 
|---|
| 120 | // This should be enough in most cases. | 
|---|
| 121 | u_int32_t next4Bytes | 
|---|
| 122 | = (fTo[i]<<24)|(fTo[i+1]<<16)|(fTo[i+2]<<8)|fTo[i+3]; | 
|---|
| 123 | i += 4; | 
|---|
| 124 | u_int32_t timeInfo = (nextByte<<(32-6))|(next4Bytes>>6); | 
|---|
| 125 | unsigned modulo_time_base = 0; | 
|---|
| 126 | u_int32_t mask = 0x80000000; | 
|---|
| 127 | while ((timeInfo&mask) != 0) { | 
|---|
| 128 | ++modulo_time_base; | 
|---|
| 129 | mask >>= 1; | 
|---|
| 130 | } | 
|---|
| 131 | mask >>= 2; | 
|---|
| 132 |  | 
|---|
| 133 | // Then, get the "vop_time_increment". | 
|---|
| 134 | unsigned vop_time_increment = 0; | 
|---|
| 135 | // First, make sure we have enough bits left for this: | 
|---|
| 136 | if ((mask>>(fNumVTIRBits-1)) != 0) { | 
|---|
| 137 | for (unsigned i = 0; i < fNumVTIRBits; ++i) { | 
|---|
| 138 | vop_time_increment |= timeInfo&mask; | 
|---|
| 139 | mask >>= 1; | 
|---|
| 140 | } | 
|---|
| 141 | while (mask != 0) { | 
|---|
| 142 | vop_time_increment >>= 1; | 
|---|
| 143 | mask >>= 1; | 
|---|
| 144 | } | 
|---|
| 145 | } | 
|---|
| 146 |  | 
|---|
| 147 | // If this is a "B" frame, then we have to tweak "presentationTime": | 
|---|
| 148 | if (!fLeavePresentationTimesUnmodified && vop_coding_type == 2/*B*/ | 
|---|
| 149 | && (fLastNonBFramePresentationTime.tv_usec > 0 || | 
|---|
| 150 | fLastNonBFramePresentationTime.tv_sec > 0)) { | 
|---|
| 151 | int timeIncrement | 
|---|
| 152 | = fLastNonBFrameVop_time_increment - vop_time_increment; | 
|---|
| 153 | if (timeIncrement<0) timeIncrement += vop_time_increment_resolution; | 
|---|
| 154 | unsigned const MILLION = 1000000; | 
|---|
| 155 | double usIncrement = vop_time_increment_resolution == 0 ? 0.0 | 
|---|
| 156 | : ((double)timeIncrement*MILLION)/vop_time_increment_resolution; | 
|---|
| 157 | unsigned secondsToSubtract = (unsigned)(usIncrement/MILLION); | 
|---|
| 158 | unsigned uSecondsToSubtract = ((unsigned)usIncrement)%MILLION; | 
|---|
| 159 |  | 
|---|
| 160 | presentationTime = fLastNonBFramePresentationTime; | 
|---|
| 161 | if ((unsigned)presentationTime.tv_usec < uSecondsToSubtract) { | 
|---|
| 162 | presentationTime.tv_usec += MILLION; | 
|---|
| 163 | if (presentationTime.tv_sec > 0) --presentationTime.tv_sec; | 
|---|
| 164 | } | 
|---|
| 165 | presentationTime.tv_usec -= uSecondsToSubtract; | 
|---|
| 166 | if ((unsigned)presentationTime.tv_sec > secondsToSubtract) { | 
|---|
| 167 | presentationTime.tv_sec -= secondsToSubtract; | 
|---|
| 168 | } else { | 
|---|
| 169 | presentationTime.tv_sec = presentationTime.tv_usec = 0; | 
|---|
| 170 | } | 
|---|
| 171 | } else { | 
|---|
| 172 | fLastNonBFramePresentationTime = presentationTime; | 
|---|
| 173 | fLastNonBFrameVop_time_increment = vop_time_increment; | 
|---|
| 174 | } | 
|---|
| 175 | } | 
|---|
| 176 | } | 
|---|
| 177 | } | 
|---|
| 178 |  | 
|---|
| 179 | // Complete delivery to the client: | 
|---|
| 180 | fFrameSize = frameSize; | 
|---|
| 181 | fNumTruncatedBytes = numTruncatedBytes; | 
|---|
| 182 | fPresentationTime = presentationTime; | 
|---|
| 183 | fDurationInMicroseconds = durationInMicroseconds; | 
|---|
| 184 | afterGetting(this); | 
|---|
| 185 | } | 
|---|
| 186 |  | 
|---|
| 187 | Boolean MPEG4VideoStreamDiscreteFramer::getNextFrameBit(u_int8_t& result) { | 
|---|
| 188 | if (fNumBitsSeenSoFar/8 >= fNumConfigBytes) return False; | 
|---|
| 189 |  | 
|---|
| 190 | u_int8_t nextByte = fConfigBytes[fNumBitsSeenSoFar/8]; | 
|---|
| 191 | result = (nextByte>>(7-fNumBitsSeenSoFar%8))&1; | 
|---|
| 192 | ++fNumBitsSeenSoFar; | 
|---|
| 193 | return True; | 
|---|
| 194 | } | 
|---|
| 195 |  | 
|---|
| 196 | Boolean MPEG4VideoStreamDiscreteFramer::getNextFrameBits(unsigned numBits, | 
|---|
| 197 | u_int32_t& result) { | 
|---|
| 198 | result = 0; | 
|---|
| 199 | for (unsigned i = 0; i < numBits; ++i) { | 
|---|
| 200 | u_int8_t nextBit; | 
|---|
| 201 | if (!getNextFrameBit(nextBit)) return False; | 
|---|
| 202 | result = (result<<1)|nextBit; | 
|---|
| 203 | } | 
|---|
| 204 | return True; | 
|---|
| 205 | } | 
|---|
| 206 |  | 
|---|
| 207 | void MPEG4VideoStreamDiscreteFramer::() { | 
|---|
| 208 | // Begin by moving to the VOL header: | 
|---|
| 209 | unsigned i; | 
|---|
| 210 | for (i = 3; i < fNumConfigBytes; ++i) { | 
|---|
| 211 | if (fConfigBytes[i] >= 0x20 && fConfigBytes[i] <= 0x2F | 
|---|
| 212 | && fConfigBytes[i-1] == 1 | 
|---|
| 213 | && fConfigBytes[i-2] == 0 && fConfigBytes[i-3] == 0) { | 
|---|
| 214 | ++i; | 
|---|
| 215 | break; | 
|---|
| 216 | } | 
|---|
| 217 | } | 
|---|
| 218 |  | 
|---|
| 219 | fNumBitsSeenSoFar = 8*i + 9; | 
|---|
| 220 | do { | 
|---|
| 221 | u_int8_t is_object_layer_identifier; | 
|---|
| 222 | if (!getNextFrameBit(is_object_layer_identifier)) break; | 
|---|
| 223 | if (is_object_layer_identifier) fNumBitsSeenSoFar += 7; | 
|---|
| 224 |  | 
|---|
| 225 | u_int32_t aspect_ratio_info; | 
|---|
| 226 | if (!getNextFrameBits(4, aspect_ratio_info)) break; | 
|---|
| 227 | if (aspect_ratio_info == 15 /*extended_PAR*/) fNumBitsSeenSoFar += 16; | 
|---|
| 228 |  | 
|---|
| 229 | u_int8_t vol_control_parameters; | 
|---|
| 230 | if (!getNextFrameBit(vol_control_parameters)) break; | 
|---|
| 231 | if (vol_control_parameters) { | 
|---|
| 232 | fNumBitsSeenSoFar += 3; // chroma_format; low_delay | 
|---|
| 233 | u_int8_t vbw_parameters; | 
|---|
| 234 | if (!getNextFrameBit(vbw_parameters)) break; | 
|---|
| 235 | if (vbw_parameters) fNumBitsSeenSoFar += 79; | 
|---|
| 236 | } | 
|---|
| 237 |  | 
|---|
| 238 | fNumBitsSeenSoFar += 2; // video_object_layer_shape | 
|---|
| 239 | u_int8_t marker_bit; | 
|---|
| 240 | if (!getNextFrameBit(marker_bit)) break; | 
|---|
| 241 | if (marker_bit != 1) break; // sanity check | 
|---|
| 242 |  | 
|---|
| 243 | if (!getNextFrameBits(16, vop_time_increment_resolution)) break; | 
|---|
| 244 | if (vop_time_increment_resolution == 0) break; // shouldn't happen | 
|---|
| 245 |  | 
|---|
| 246 | // Compute how many bits are necessary to represent this: | 
|---|
| 247 | fNumVTIRBits = 0; | 
|---|
| 248 | for (unsigned test = vop_time_increment_resolution; test>0; test /= 2) { | 
|---|
| 249 | ++fNumVTIRBits; | 
|---|
| 250 | } | 
|---|
| 251 | } while (0); | 
|---|
| 252 | } | 
|---|
| 253 |  | 
|---|