00001 /********** 00002 This library is free software; you can redistribute it and/or modify it under 00003 the terms of the GNU Lesser General Public License as published by the 00004 Free Software Foundation; either version 2.1 of the License, or (at your 00005 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) 00006 00007 This library is distributed in the hope that it will be useful, but WITHOUT 00008 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00009 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 00010 more details. 00011 00012 You should have received a copy of the GNU Lesser General Public License 00013 along with this library; if not, write to the Free Software Foundation, Inc., 00014 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00015 **********/ 00016 // "liveMedia" 00017 // Copyright (c) 1996-2013 Live Networks, Inc. All rights reserved. 00018 // A template for a MediaSource encapsulating an audio/video input device 00019 // 00020 // NOTE: Sections of this code labeled "%%% TO BE WRITTEN %%%" are incomplete, and need to be written by the programmer 00021 // (depending on the features of the particular device). 00022 // Implementation 00023 00024 #include "DeviceSource.hh" 00025 #include <GroupsockHelper.hh> // for "gettimeofday()" 00026 00027 DeviceSource* 00028 DeviceSource::createNew(UsageEnvironment& env, 00029 DeviceParameters params) { 00030 return new DeviceSource(env, params); 00031 } 00032 00033 EventTriggerId DeviceSource::eventTriggerId = 0; 00034 00035 unsigned DeviceSource::referenceCount = 0; 00036 00037 DeviceSource::DeviceSource(UsageEnvironment& env, 00038 DeviceParameters params) 00039 : FramedSource(env), fParams(params) { 00040 if (referenceCount == 0) { 00041 // Any global initialization of the device would be done here: 00042 //%%% TO BE WRITTEN %%% 00043 } 00044 ++referenceCount; 00045 00046 // Any instance-specific initialization of the device would be done here: 00047 //%%% TO BE WRITTEN %%% 00048 00049 // We arrange here for our "deliverFrame" member function to be called 00050 // whenever the next frame of data becomes available from the device. 00051 // 00052 // If the device can be accessed as a readable socket, then one easy way to do this is using a call to 00053 // envir().taskScheduler().turnOnBackgroundReadHandling( ... ) 00054 // (See examples of this call in the "liveMedia" directory.) 00055 // 00056 // If, however, the device *cannot* be accessed as a readable socket, then instead we can implement it using 'event triggers': 00057 // Create an 'event trigger' for this device (if it hasn't already been done): 00058 if (eventTriggerId == 0) { 00059 eventTriggerId = envir().taskScheduler().createEventTrigger(deliverFrame0); 00060 } 00061 } 00062 00063 DeviceSource::~DeviceSource() { 00064 // Any instance-specific 'destruction' (i.e., resetting) of the device would be done here: 00065 //%%% TO BE WRITTEN %%% 00066 00067 --referenceCount; 00068 if (referenceCount == 0) { 00069 // Any global 'destruction' (i.e., resetting) of the device would be done here: 00070 //%%% TO BE WRITTEN %%% 00071 00072 // Reclaim our 'event trigger' 00073 envir().taskScheduler().deleteEventTrigger(eventTriggerId); 00074 eventTriggerId = 0; 00075 } 00076 } 00077 00078 void DeviceSource::doGetNextFrame() { 00079 // This function is called (by our 'downstream' object) when it asks for new data. 00080 00081 // Note: If, for some reason, the source device stops being readable (e.g., it gets closed), then you do the following: 00082 if (0 /* the source stops being readable */ /*%%% TO BE WRITTEN %%%*/) { 00083 handleClosure(this); 00084 return; 00085 } 00086 00087 // If a new frame of data is immediately available to be delivered, then do this now: 00088 if (0 /* a new frame of data is immediately available to be delivered*/ /*%%% TO BE WRITTEN %%%*/) { 00089 deliverFrame(); 00090 } 00091 00092 // No new data is immediately available to be delivered. We don't do anything more here. 00093 // Instead, our event trigger must be called (e.g., from a separate thread) when new data becomes available. 00094 } 00095 00096 void DeviceSource::deliverFrame0(void* clientData) { 00097 ((DeviceSource*)clientData)->deliverFrame(); 00098 } 00099 00100 void DeviceSource::deliverFrame() { 00101 // This function is called when new frame data is available from the device. 00102 // We deliver this data by copying it to the 'downstream' object, using the following parameters (class members): 00103 // 'in' parameters (these should *not* be modified by this function): 00104 // fTo: The frame data is copied to this address. 00105 // (Note that the variable "fTo" is *not* modified. Instead, 00106 // the frame data is copied to the address pointed to by "fTo".) 00107 // fMaxSize: This is the maximum number of bytes that can be copied 00108 // (If the actual frame is larger than this, then it should 00109 // be truncated, and "fNumTruncatedBytes" set accordingly.) 00110 // 'out' parameters (these are modified by this function): 00111 // fFrameSize: Should be set to the delivered frame size (<= fMaxSize). 00112 // fNumTruncatedBytes: Should be set iff the delivered frame would have been 00113 // bigger than "fMaxSize", in which case it's set to the number of bytes 00114 // that have been omitted. 00115 // fPresentationTime: Should be set to the frame's presentation time 00116 // (seconds, microseconds). This time must be aligned with 'wall-clock time' - i.e., the time that you would get 00117 // by calling "gettimeofday()". 00118 // fDurationInMicroseconds: Should be set to the frame's duration, if known. 00119 // If, however, the device is a 'live source' (e.g., encoded from a camera or microphone), then we probably don't need 00120 // to set this variable, because - in this case - data will never arrive 'early'. 00121 // Note the code below. 00122 00123 if (!isCurrentlyAwaitingData()) return; // we're not ready for the data yet 00124 00125 u_int8_t* newFrameDataStart = (u_int8_t*)0xDEADBEEF; //%%% TO BE WRITTEN %%% 00126 unsigned newFrameSize = 0; //%%% TO BE WRITTEN %%% 00127 00128 // Deliver the data here: 00129 if (newFrameSize > fMaxSize) { 00130 fFrameSize = fMaxSize; 00131 fNumTruncatedBytes = newFrameSize - fMaxSize; 00132 } else { 00133 fFrameSize = newFrameSize; 00134 } 00135 gettimeofday(&fPresentationTime, NULL); // If you have a more accurate time - e.g., from an encoder - then use that instead. 00136 // If the device is *not* a 'live source' (e.g., it comes instead from a file or buffer), then set "fDurationInMicroseconds" here. 00137 memmove(fTo, newFrameDataStart, fFrameSize); 00138 00139 // After delivering the data, inform the reader that it is now available: 00140 FramedSource::afterGetting(this); 00141 } 00142 00143 00144 // The following code would be called to signal that a new frame of data has become available. 00145 // This (unlike other "LIVE555 Streaming Media" library code) may be called from a separate thread. 00146 // (Note, however, that "triggerEvent()" cannot be called with the same 'event trigger id' from different threads. 00147 // Also, if you want to have multiple device threads, each one using a different 'event trigger id', then you will need 00148 // to make "eventTriggerId" a non-static member variable of "DeviceSource".) 00149 void signalNewFrameData() { 00150 TaskScheduler* ourScheduler = NULL; //%%% TO BE WRITTEN %%% 00151 DeviceSource* ourDevice = NULL; //%%% TO BE WRITTEN %%% 00152 00153 if (ourScheduler != NULL) { // sanity check 00154 ourScheduler->triggerEvent(DeviceSource::eventTriggerId, ourDevice); 00155 } 00156 }
1.5.2