| 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 | // Author Bernhard Feiten |
| 19 | // A filter that breaks up an H.263plus video stream into frames. |
| 20 | // |
| 21 | |
| 22 | #include "H263plusVideoStreamFramer.hh" |
| 23 | #include "H263plusVideoStreamParser.hh" |
| 24 | |
| 25 | #include <string.h> |
| 26 | #include <GroupsockHelper.hh> |
| 27 | |
| 28 | |
| 29 | /////////////////////////////////////////////////////////////////////////////// |
| 30 | ////////// H263plusVideoStreamFramer implementation ////////// |
| 31 | //public/////////////////////////////////////////////////////////////////////// |
| 32 | H263plusVideoStreamFramer* H263plusVideoStreamFramer::createNew( |
| 33 | UsageEnvironment& env, |
| 34 | FramedSource* inputSource) |
| 35 | { |
| 36 | // Need to add source type checking here??? ##### |
| 37 | H263plusVideoStreamFramer* fr; |
| 38 | fr = new H263plusVideoStreamFramer(env, inputSource); |
| 39 | return fr; |
| 40 | } |
| 41 | |
| 42 | |
| 43 | /////////////////////////////////////////////////////////////////////////////// |
| 44 | H263plusVideoStreamFramer::H263plusVideoStreamFramer( |
| 45 | UsageEnvironment& env, |
| 46 | FramedSource* inputSource, |
| 47 | Boolean createParser) |
| 48 | : FramedFilter(env, inputSource), |
| 49 | fFrameRate(0.0), // until we learn otherwise |
| 50 | fPictureEndMarker(False) |
| 51 | { |
| 52 | // Use the current wallclock time as the base 'presentation time': |
| 53 | gettimeofday(&fPresentationTimeBase, NULL); |
| 54 | fParser = createParser ? new H263plusVideoStreamParser(this, inputSource) : NULL; |
| 55 | } |
| 56 | |
| 57 | /////////////////////////////////////////////////////////////////////////////// |
| 58 | H263plusVideoStreamFramer::~H263plusVideoStreamFramer() |
| 59 | { |
| 60 | delete fParser; |
| 61 | } |
| 62 | |
| 63 | |
| 64 | /////////////////////////////////////////////////////////////////////////////// |
| 65 | void H263plusVideoStreamFramer::doGetNextFrame() |
| 66 | { |
| 67 | fParser->registerReadInterest(fTo, fMaxSize); |
| 68 | continueReadProcessing(); |
| 69 | } |
| 70 | |
| 71 | |
| 72 | /////////////////////////////////////////////////////////////////////////////// |
| 73 | Boolean H263plusVideoStreamFramer::isH263plusVideoStreamFramer() const |
| 74 | { |
| 75 | return True; |
| 76 | } |
| 77 | |
| 78 | /////////////////////////////////////////////////////////////////////////////// |
| 79 | void H263plusVideoStreamFramer::continueReadProcessing( |
| 80 | void* clientData, |
| 81 | unsigned char* /*ptr*/, unsigned /*size*/, |
| 82 | struct timeval /*presentationTime*/) |
| 83 | { |
| 84 | H263plusVideoStreamFramer* framer = (H263plusVideoStreamFramer*)clientData; |
| 85 | framer->continueReadProcessing(); |
| 86 | } |
| 87 | |
| 88 | /////////////////////////////////////////////////////////////////////////////// |
| 89 | void H263plusVideoStreamFramer::continueReadProcessing() |
| 90 | { |
| 91 | unsigned acquiredFrameSize; |
| 92 | |
| 93 | u_int64_t frameDuration; // in ms |
| 94 | |
| 95 | acquiredFrameSize = fParser->parse(frameDuration); |
| 96 | // Calculate some average bitrate information (to be adapted) |
| 97 | // avgBitrate = (totalBytes * 8 * H263_TIMESCALE) / totalDuration; |
| 98 | |
| 99 | if (acquiredFrameSize > 0) { |
| 100 | // We were able to acquire a frame from the input. |
| 101 | // It has already been copied to the reader's space. |
| 102 | fFrameSize = acquiredFrameSize; |
| 103 | // fNumTruncatedBytes = fParser->numTruncatedBytes(); // not needed so far |
| 104 | |
| 105 | fFrameRate = frameDuration == 0 ? 0.0 : 1000./(long)frameDuration; |
| 106 | |
| 107 | // Compute "fPresentationTime" |
| 108 | if (acquiredFrameSize == 5) // first frame |
| 109 | fPresentationTime = fPresentationTimeBase; |
| 110 | else |
| 111 | fPresentationTime.tv_usec += (long) frameDuration*1000; |
| 112 | |
| 113 | while (fPresentationTime.tv_usec >= 1000000) { |
| 114 | fPresentationTime.tv_usec -= 1000000; |
| 115 | ++fPresentationTime.tv_sec; |
| 116 | } |
| 117 | |
| 118 | // Compute "fDurationInMicroseconds" |
| 119 | fDurationInMicroseconds = (unsigned int) frameDuration*1000;; |
| 120 | |
| 121 | // Call our own 'after getting' function. Because we're not a 'leaf' |
| 122 | // source, we can call this directly, without risking infinite recursion. |
| 123 | afterGetting(this); |
| 124 | } else { |
| 125 | // We were unable to parse a complete frame from the input, because: |
| 126 | // - we had to read more data from the source stream, or |
| 127 | // - the source stream has ended. |
| 128 | } |
| 129 | } |
| 130 | |