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 | |