| 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 template for a MediaSource encapsulating an audio/video input device |
| 19 | // |
| 20 | // NOTE: Sections of this code labeled "%%% TO BE WRITTEN %%%" are incomplete, and need to be written by the programmer |
| 21 | // (depending on the features of the particular device). |
| 22 | // Implementation |
| 23 | |
| 24 | #include "DeviceSource.hh" |
| 25 | #include <GroupsockHelper.hh> // for "gettimeofday()" |
| 26 | |
| 27 | DeviceSource* |
| 28 | DeviceSource::createNew(UsageEnvironment& env, |
| 29 | DeviceParameters params) { |
| 30 | return new DeviceSource(env, params); |
| 31 | } |
| 32 | |
| 33 | EventTriggerId DeviceSource::eventTriggerId = 0; |
| 34 | |
| 35 | unsigned DeviceSource::referenceCount = 0; |
| 36 | |
| 37 | DeviceSource::DeviceSource(UsageEnvironment& env, |
| 38 | DeviceParameters params) |
| 39 | : FramedSource(env), fParams(params) { |
| 40 | if (referenceCount == 0) { |
| 41 | // Any global initialization of the device would be done here: |
| 42 | //%%% TO BE WRITTEN %%% |
| 43 | } |
| 44 | ++referenceCount; |
| 45 | |
| 46 | // Any instance-specific initialization of the device would be done here: |
| 47 | //%%% TO BE WRITTEN %%% |
| 48 | |
| 49 | // We arrange here for our "deliverFrame" member function to be called |
| 50 | // whenever the next frame of data becomes available from the device. |
| 51 | // |
| 52 | // If the device can be accessed as a readable socket, then one easy way to do this is using a call to |
| 53 | // envir().taskScheduler().turnOnBackgroundReadHandling( ... ) |
| 54 | // (See examples of this call in the "liveMedia" directory.) |
| 55 | // |
| 56 | // If, however, the device *cannot* be accessed as a readable socket, then instead we can implement it using 'event triggers': |
| 57 | // Create an 'event trigger' for this device (if it hasn't already been done): |
| 58 | if (eventTriggerId == 0) { |
| 59 | eventTriggerId = envir().taskScheduler().createEventTrigger(deliverFrame0); |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | DeviceSource::~DeviceSource() { |
| 64 | // Any instance-specific 'destruction' (i.e., resetting) of the device would be done here: |
| 65 | //%%% TO BE WRITTEN %%% |
| 66 | |
| 67 | --referenceCount; |
| 68 | if (referenceCount == 0) { |
| 69 | // Any global 'destruction' (i.e., resetting) of the device would be done here: |
| 70 | //%%% TO BE WRITTEN %%% |
| 71 | |
| 72 | // Reclaim our 'event trigger' |
| 73 | envir().taskScheduler().deleteEventTrigger(eventTriggerId); |
| 74 | eventTriggerId = 0; |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | void DeviceSource::doGetNextFrame() { |
| 79 | // This function is called (by our 'downstream' object) when it asks for new data. |
| 80 | |
| 81 | // Note: If, for some reason, the source device stops being readable (e.g., it gets closed), then you do the following: |
| 82 | if (0 /* the source stops being readable */ /*%%% TO BE WRITTEN %%%*/) { |
| 83 | handleClosure(); |
| 84 | return; |
| 85 | } |
| 86 | |
| 87 | // If a new frame of data is immediately available to be delivered, then do this now: |
| 88 | if (0 /* a new frame of data is immediately available to be delivered*/ /*%%% TO BE WRITTEN %%%*/) { |
| 89 | deliverFrame(); |
| 90 | } |
| 91 | |
| 92 | // No new data is immediately available to be delivered. We don't do anything more here. |
| 93 | // Instead, our event trigger must be called (e.g., from a separate thread) when new data becomes available. |
| 94 | } |
| 95 | |
| 96 | void DeviceSource::deliverFrame0(void* clientData) { |
| 97 | ((DeviceSource*)clientData)->deliverFrame(); |
| 98 | } |
| 99 | |
| 100 | void DeviceSource::deliverFrame() { |
| 101 | // This function is called when new frame data is available from the device. |
| 102 | // We deliver this data by copying it to the 'downstream' object, using the following parameters (class members): |
| 103 | // 'in' parameters (these should *not* be modified by this function): |
| 104 | // fTo: The frame data is copied to this address. |
| 105 | // (Note that the variable "fTo" is *not* modified. Instead, |
| 106 | // the frame data is copied to the address pointed to by "fTo".) |
| 107 | // fMaxSize: This is the maximum number of bytes that can be copied |
| 108 | // (If the actual frame is larger than this, then it should |
| 109 | // be truncated, and "fNumTruncatedBytes" set accordingly.) |
| 110 | // 'out' parameters (these are modified by this function): |
| 111 | // fFrameSize: Should be set to the delivered frame size (<= fMaxSize). |
| 112 | // fNumTruncatedBytes: Should be set iff the delivered frame would have been |
| 113 | // bigger than "fMaxSize", in which case it's set to the number of bytes |
| 114 | // that have been omitted. |
| 115 | // fPresentationTime: Should be set to the frame's presentation time |
| 116 | // (seconds, microseconds). This time must be aligned with 'wall-clock time' - i.e., the time that you would get |
| 117 | // by calling "gettimeofday()". |
| 118 | // fDurationInMicroseconds: Should be set to the frame's duration, if known. |
| 119 | // If, however, the device is a 'live source' (e.g., encoded from a camera or microphone), then we probably don't need |
| 120 | // to set this variable, because - in this case - data will never arrive 'early'. |
| 121 | // Note the code below. |
| 122 | |
| 123 | if (!isCurrentlyAwaitingData()) return; // we're not ready for the data yet |
| 124 | |
| 125 | u_int8_t* newFrameDataStart = (u_int8_t*)0xDEADBEEF; //%%% TO BE WRITTEN %%% |
| 126 | unsigned newFrameSize = 0; //%%% TO BE WRITTEN %%% |
| 127 | |
| 128 | // Deliver the data here: |
| 129 | if (newFrameSize > fMaxSize) { |
| 130 | fFrameSize = fMaxSize; |
| 131 | fNumTruncatedBytes = newFrameSize - fMaxSize; |
| 132 | } else { |
| 133 | fFrameSize = newFrameSize; |
| 134 | } |
| 135 | gettimeofday(&fPresentationTime, NULL); // If you have a more accurate time - e.g., from an encoder - then use that instead. |
| 136 | // If the device is *not* a 'live source' (e.g., it comes instead from a file or buffer), then set "fDurationInMicroseconds" here. |
| 137 | memmove(fTo, newFrameDataStart, fFrameSize); |
| 138 | |
| 139 | // After delivering the data, inform the reader that it is now available: |
| 140 | FramedSource::afterGetting(this); |
| 141 | } |
| 142 | |
| 143 | |
| 144 | // The following code would be called to signal that a new frame of data has become available. |
| 145 | // This (unlike other "LIVE555 Streaming Media" library code) may be called from a separate thread. |
| 146 | // (Note, however, that "triggerEvent()" cannot be called with the same 'event trigger id' from different threads. |
| 147 | // Also, if you want to have multiple device threads, each one using a different 'event trigger id', then you will need |
| 148 | // to make "eventTriggerId" a non-static member variable of "DeviceSource".) |
| 149 | void signalNewFrameData() { |
| 150 | TaskScheduler* ourScheduler = NULL; //%%% TO BE WRITTEN %%% |
| 151 | DeviceSource* ourDevice = NULL; //%%% TO BE WRITTEN %%% |
| 152 | |
| 153 | if (ourScheduler != NULL) { // sanity check |
| 154 | ourScheduler->triggerEvent(DeviceSource::eventTriggerId, ourDevice); |
| 155 | } |
| 156 | } |
| 157 | |