liveMedia/DeviceSource.cpp

Go to the documentation of this file.
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-2014 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();
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 }

Generated on Tue Mar 25 14:35:34 2014 for live by  doxygen 1.5.2