mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Tweaks to the win32 camera capture code to reduce CPU load.
This commit is contained in:
parent
b80bb4bf38
commit
ea16741b3d
8 changed files with 308 additions and 342 deletions
|
|
@ -142,6 +142,68 @@ private:
|
|||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class DrawableComponent : public Component,
|
||||
public ValueTree::Listener
|
||||
{
|
||||
public:
|
||||
DrawableComponent (const ValueTree& drawable_)
|
||||
{
|
||||
setDrawable (drawable_);
|
||||
}
|
||||
|
||||
~DrawableComponent()
|
||||
{
|
||||
}
|
||||
|
||||
void setDrawable (const ValueTree& newDrawable)
|
||||
{
|
||||
drawable.removeListener (this);
|
||||
drawable = newDrawable;
|
||||
drawable.addListener (this);
|
||||
drawableObject = Drawable::createFromValueTree (drawable, 0); // xxx image provider missing
|
||||
resized();
|
||||
repaint();
|
||||
}
|
||||
|
||||
void paint (Graphics& g)
|
||||
{
|
||||
if (drawableObject != 0)
|
||||
drawableObject->drawAt (g, 0, 0, 1.0f);
|
||||
}
|
||||
|
||||
void resized()
|
||||
{
|
||||
DrawableComposite* dc = dynamic_cast <DrawableComposite*> (static_cast <Drawable*> (drawableObject));
|
||||
|
||||
if (dc != 0)
|
||||
{
|
||||
dc->setMarker (DrawableComposite::contentLeftMarkerName, true, RelativeCoordinate (0));
|
||||
dc->setMarker (DrawableComposite::contentTopMarkerName, false, RelativeCoordinate (0));
|
||||
dc->setMarker (DrawableComposite::contentRightMarkerName, true, RelativeCoordinate (getWidth()));
|
||||
dc->setMarker (DrawableComposite::contentBottomMarkerName, false, RelativeCoordinate (getHeight()));
|
||||
}
|
||||
}
|
||||
|
||||
void valueTreePropertyChanged (ValueTree&, const Identifier&) { updateGraphics(); }
|
||||
void valueTreeChildrenChanged (ValueTree&) { updateGraphics(); }
|
||||
void valueTreeParentChanged (ValueTree&) { updateGraphics(); }
|
||||
|
||||
private:
|
||||
ValueTree drawable;
|
||||
ScopedPointer<Drawable> drawableObject;
|
||||
|
||||
void updateGraphics()
|
||||
{
|
||||
if (drawableObject != 0)
|
||||
{
|
||||
const Rectangle<float> dirtyArea (drawableObject->refreshFromValueTree (drawable, 0));
|
||||
repaint (dirtyArea.getSmallestIntegerContainer());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1110,8 +1110,6 @@ public:
|
|||
#endif
|
||||
|
||||
//==============================================================================
|
||||
const int numGroups = 4;
|
||||
|
||||
class WidgetsDemo : public Component,
|
||||
public ButtonListener
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18349,6 +18349,28 @@ void ValueTree::SharedObject::moveChild (int currentIndex, int newIndex, UndoMan
|
|||
}
|
||||
}
|
||||
|
||||
void ValueTree::SharedObject::reorderChildren (const ReferenceCountedArray <SharedObject>& newOrder, UndoManager* undoManager)
|
||||
{
|
||||
jassert (newOrder.size() == children.size());
|
||||
|
||||
if (undoManager == 0)
|
||||
{
|
||||
children = newOrder;
|
||||
sendChildChangeMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < children.size(); ++i)
|
||||
{
|
||||
if (children.getUnchecked(i) != newOrder.getUnchecked(i))
|
||||
{
|
||||
jassert (children.contains (newOrder.getUnchecked(i)));
|
||||
moveChild (children.indexOf (newOrder.getUnchecked(i)), i, undoManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ValueTree::SharedObject::isEquivalentTo (const SharedObject& other) const
|
||||
{
|
||||
if (type != other.type
|
||||
|
|
@ -44257,19 +44279,9 @@ void DrawableButton::paintButton (Graphics& g,
|
|||
if (imageToDraw != 0)
|
||||
{
|
||||
if (style == ImageRaw)
|
||||
{
|
||||
imageToDraw->draw (g, 1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
imageToDraw->drawWithin (g,
|
||||
imageSpace.getX(),
|
||||
imageSpace.getY(),
|
||||
imageSpace.getWidth(),
|
||||
imageSpace.getHeight(),
|
||||
RectanglePlacement::centred,
|
||||
1.0f);
|
||||
}
|
||||
imageToDraw->drawWithin (g, imageSpace.toFloat(), RectanglePlacement::centred, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -44831,13 +44843,15 @@ void ToolbarButton::paintButtonArea (Graphics& g,
|
|||
if (getToggleState() && toggledOnImage != 0)
|
||||
d = toggledOnImage;
|
||||
|
||||
const Rectangle<float> area (0.0f, 0.0f, (float) width, (float) height);
|
||||
|
||||
if (! isEnabled())
|
||||
{
|
||||
Image im (Image::ARGB, width, height, true);
|
||||
|
||||
{
|
||||
Graphics g2 (im);
|
||||
d->drawWithin (g2, 0, 0, width, height, RectanglePlacement::centred, 1.0f);
|
||||
d->drawWithin (g2, area, RectanglePlacement::centred, 1.0f);
|
||||
}
|
||||
|
||||
im.desaturate();
|
||||
|
|
@ -44845,7 +44859,7 @@ void ToolbarButton::paintButtonArea (Graphics& g,
|
|||
}
|
||||
else
|
||||
{
|
||||
d->drawWithin (g, 0, 0, width, height, RectanglePlacement::centred, 1.0f);
|
||||
d->drawWithin (g, area, RectanglePlacement::centred, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71698,7 +71712,7 @@ public:
|
|||
|
||||
if (current != 0)
|
||||
{
|
||||
registerMouseDown (screenPos, time, current);
|
||||
registerMouseDown (screenPos, time, current, buttonState);
|
||||
sendMouseDown (current, screenPos, time);
|
||||
}
|
||||
}
|
||||
|
|
@ -71845,16 +71859,10 @@ public:
|
|||
|
||||
for (int i = 1; i < numElementsInArray (mouseDowns); ++i)
|
||||
{
|
||||
if (mouseDowns[0].time - mouseDowns[i].time < (int) (MouseEvent::getDoubleClickTimeout() * (1.0 + 0.25 * (i - 1)))
|
||||
&& abs (mouseDowns[0].position.getX() - mouseDowns[i].position.getX()) < 8
|
||||
&& abs (mouseDowns[0].position.getY() - mouseDowns[i].position.getY()) < 8)
|
||||
{
|
||||
if (mouseDowns[0].canBePartOfMultipleClickWith (mouseDowns[1], (int) (MouseEvent::getDoubleClickTimeout() * (1.0 + 0.25 * (i - 1)))))
|
||||
++numClicks;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71970,13 +71978,23 @@ private:
|
|||
Point<int> position;
|
||||
int64 time;
|
||||
Component* component;
|
||||
ModifierKeys buttons;
|
||||
|
||||
bool canBePartOfMultipleClickWith (const RecentMouseDown& other, int maxTimeBetween) const
|
||||
{
|
||||
return time - other.time < maxTimeBetween
|
||||
&& abs (position.getX() - other.position.getX()) < 8
|
||||
&& abs (position.getY() - other.position.getY()) < 8
|
||||
&& buttons == other.buttons;;
|
||||
}
|
||||
};
|
||||
|
||||
RecentMouseDown mouseDowns[4];
|
||||
bool mouseMovedSignificantlySincePressed;
|
||||
int64 lastTime;
|
||||
|
||||
void registerMouseDown (const Point<int>& screenPos, const int64 time, Component* const component) throw()
|
||||
void registerMouseDown (const Point<int>& screenPos, const int64 time,
|
||||
Component* const component, const ModifierKeys& modifiers) throw()
|
||||
{
|
||||
for (int i = numElementsInArray (mouseDowns); --i > 0;)
|
||||
mouseDowns[i] = mouseDowns[i - 1];
|
||||
|
|
@ -71984,6 +72002,7 @@ private:
|
|||
mouseDowns[0].position = screenPos;
|
||||
mouseDowns[0].time = time;
|
||||
mouseDowns[0].component = component;
|
||||
mouseDowns[0].buttons = modifiers.withOnlyMouseButtons();
|
||||
mouseMovedSignificantlySincePressed = false;
|
||||
}
|
||||
|
||||
|
|
@ -85932,21 +85951,21 @@ void RectanglePlacement::applyTo (double& x, double& y,
|
|||
}
|
||||
}
|
||||
|
||||
const AffineTransform RectanglePlacement::getTransformToFit (float x, float y,
|
||||
float w, float h,
|
||||
const float dx, const float dy,
|
||||
const float dw, const float dh) const throw()
|
||||
const AffineTransform RectanglePlacement::getTransformToFit (const Rectangle<float>& source, const Rectangle<float>& destination) const throw()
|
||||
{
|
||||
if (w == 0 || h == 0)
|
||||
if (source.isEmpty())
|
||||
return AffineTransform::identity;
|
||||
|
||||
const float scaleX = dw / w;
|
||||
const float scaleY = dh / h;
|
||||
float w = source.getWidth();
|
||||
float h = source.getHeight();
|
||||
|
||||
const float scaleX = destination.getWidth() / w;
|
||||
const float scaleY = destination.getHeight() / h;
|
||||
|
||||
if ((flags & stretchToFit) != 0)
|
||||
return AffineTransform::translation (-x, -y)
|
||||
return AffineTransform::translation (-source.getX(), -source.getY())
|
||||
.scaled (scaleX, scaleY)
|
||||
.translated (dx, dy);
|
||||
.translated (destination.getX(), destination.getY());
|
||||
|
||||
float scale = (flags & fillDestination) != 0 ? jmax (scaleX, scaleY)
|
||||
: jmin (scaleX, scaleY);
|
||||
|
|
@ -85960,21 +85979,20 @@ const AffineTransform RectanglePlacement::getTransformToFit (float x, float y,
|
|||
w *= scale;
|
||||
h *= scale;
|
||||
|
||||
float newX = dx;
|
||||
float newX = destination.getX();
|
||||
float newY = destination.getY();
|
||||
|
||||
if ((flags & xRight) != 0)
|
||||
newX += dw - w; // right
|
||||
newX += destination.getWidth() - w; // right
|
||||
else if ((flags & xLeft) == 0)
|
||||
newX += (dw - w) / 2.0f; // centre
|
||||
|
||||
float newY = dy;
|
||||
newX += (destination.getWidth() - w) / 2.0f; // centre
|
||||
|
||||
if ((flags & yBottom) != 0)
|
||||
newY += dh - h; // bottom
|
||||
newY += destination.getHeight() - h; // bottom
|
||||
else if ((flags & yTop) == 0)
|
||||
newY += (dh - h) / 2.0f; // centre
|
||||
newY += (destination.getHeight() - h) / 2.0f; // centre
|
||||
|
||||
return AffineTransform::translation (-x, -y)
|
||||
return AffineTransform::translation (-source.getX(), -source.getY())
|
||||
.scaled (scale, scale)
|
||||
.translated (newX, newY);
|
||||
}
|
||||
|
|
@ -86015,22 +86033,12 @@ void Drawable::drawAt (Graphics& g, const float x, const float y, const float op
|
|||
}
|
||||
|
||||
void Drawable::drawWithin (Graphics& g,
|
||||
const int destX,
|
||||
const int destY,
|
||||
const int destW,
|
||||
const int destH,
|
||||
const Rectangle<float>& destArea,
|
||||
const RectanglePlacement& placement,
|
||||
const float opacity) const
|
||||
{
|
||||
if (destW > 0 && destH > 0)
|
||||
{
|
||||
Rectangle<float> bounds (getBounds());
|
||||
|
||||
draw (g, opacity,
|
||||
placement.getTransformToFit (bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(),
|
||||
(float) destX, (float) destY,
|
||||
(float) destW, (float) destH));
|
||||
}
|
||||
if (! destArea.isEmpty())
|
||||
draw (g, opacity, placement.getTransformToFit (getBounds(), destArea));
|
||||
}
|
||||
|
||||
Drawable* Drawable::createFromImageData (const void* data, const size_t numBytes)
|
||||
|
|
@ -88190,8 +88198,8 @@ public:
|
|||
const RectanglePlacement placement (placementFlags);
|
||||
|
||||
newState.transform
|
||||
= placement.getTransformToFit (vx, vy, vw, vh,
|
||||
0.0f, 0.0f, newState.width, newState.height)
|
||||
= placement.getTransformToFit (Rectangle<float> (vx, vy, vw, vh),
|
||||
Rectangle<float> (0.0f, 0.0f, newState.width, newState.height))
|
||||
.followedBy (newState.transform);
|
||||
}
|
||||
}
|
||||
|
|
@ -249243,8 +249251,7 @@ void MidiOutput::sendMessageNow (const MidiMessage& message)
|
|||
#define log(a) {}
|
||||
#endif
|
||||
|
||||
#define JUCE_ASIOCALLBACK // should probably use this to define the callback type, but
|
||||
// the asio header doesn't actually specify a calling convention for the functions..
|
||||
#define JUCE_ASIOCALLBACK __cdecl
|
||||
|
||||
#if ASIO_DEBUGGING
|
||||
static void logError (const String& context, long error)
|
||||
|
|
@ -249347,40 +249354,15 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
const StringArray getOutputChannelNames()
|
||||
{
|
||||
return outputChannelNames;
|
||||
}
|
||||
const StringArray getOutputChannelNames() { return outputChannelNames; }
|
||||
const StringArray getInputChannelNames() { return inputChannelNames; }
|
||||
|
||||
const StringArray getInputChannelNames()
|
||||
{
|
||||
return inputChannelNames;
|
||||
}
|
||||
int getNumSampleRates() { return sampleRates.size(); }
|
||||
double getSampleRate (int index) { return sampleRates [index]; }
|
||||
|
||||
int getNumSampleRates()
|
||||
{
|
||||
return sampleRates.size();
|
||||
}
|
||||
|
||||
double getSampleRate (int index)
|
||||
{
|
||||
return sampleRates [index];
|
||||
}
|
||||
|
||||
int getNumBufferSizesAvailable()
|
||||
{
|
||||
return bufferSizes.size();
|
||||
}
|
||||
|
||||
int getBufferSizeSamples (int index)
|
||||
{
|
||||
return bufferSizes [index];
|
||||
}
|
||||
|
||||
int getDefaultBufferSize()
|
||||
{
|
||||
return preferredSize;
|
||||
}
|
||||
int getNumBufferSizesAvailable() { return bufferSizes.size(); }
|
||||
int getBufferSizeSamples (int index) { return bufferSizes [index]; }
|
||||
int getDefaultBufferSize() { return preferredSize; }
|
||||
|
||||
const String open (const BigInteger& inputChannels,
|
||||
const BigInteger& outputChannels,
|
||||
|
|
@ -249834,45 +249816,18 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
bool isOpen()
|
||||
{
|
||||
return isOpen_ || insideControlPanelModalLoop;
|
||||
}
|
||||
bool isOpen() { return isOpen_ || insideControlPanelModalLoop; }
|
||||
bool isPlaying() { return isASIOOpen && (currentCallback != 0); }
|
||||
|
||||
int getCurrentBufferSizeSamples()
|
||||
{
|
||||
return currentBlockSizeSamples;
|
||||
}
|
||||
int getCurrentBufferSizeSamples() { return currentBlockSizeSamples; }
|
||||
double getCurrentSampleRate() { return currentSampleRate; }
|
||||
int getCurrentBitDepth() { return currentBitDepth; }
|
||||
|
||||
double getCurrentSampleRate()
|
||||
{
|
||||
return currentSampleRate;
|
||||
}
|
||||
const BigInteger getActiveOutputChannels() const { return currentChansOut; }
|
||||
const BigInteger getActiveInputChannels() const { return currentChansIn; }
|
||||
|
||||
const BigInteger getActiveOutputChannels() const
|
||||
{
|
||||
return currentChansOut;
|
||||
}
|
||||
|
||||
const BigInteger getActiveInputChannels() const
|
||||
{
|
||||
return currentChansIn;
|
||||
}
|
||||
|
||||
int getCurrentBitDepth()
|
||||
{
|
||||
return currentBitDepth;
|
||||
}
|
||||
|
||||
int getOutputLatencyInSamples()
|
||||
{
|
||||
return outputLatency + currentBlockSizeSamples / 4;
|
||||
}
|
||||
|
||||
int getInputLatencyInSamples()
|
||||
{
|
||||
return inputLatency + currentBlockSizeSamples / 4;
|
||||
}
|
||||
int getOutputLatencyInSamples() { return outputLatency + currentBlockSizeSamples / 4; }
|
||||
int getInputLatencyInSamples() { return inputLatency + currentBlockSizeSamples / 4; }
|
||||
|
||||
void start (AudioIODeviceCallback* callback)
|
||||
{
|
||||
|
|
@ -249898,20 +249853,8 @@ public:
|
|||
lastCallback->audioDeviceStopped();
|
||||
}
|
||||
|
||||
bool isPlaying()
|
||||
{
|
||||
return isASIOOpen && (currentCallback != 0);
|
||||
}
|
||||
|
||||
const String getLastError()
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
bool hasControlPanel() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
const String getLastError() { return error; }
|
||||
bool hasControlPanel() const { return true; }
|
||||
|
||||
bool showControlPanel()
|
||||
{
|
||||
|
|
@ -250438,7 +250381,6 @@ private:
|
|||
for (i = 0; i < numActiveInputChans; ++i)
|
||||
{
|
||||
float* const dst = inBuffers[i];
|
||||
|
||||
jassert (dst != 0);
|
||||
|
||||
const char* const src = (const char*) (infos[i].buffers[bi]);
|
||||
|
|
@ -250475,16 +250417,12 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
currentCallback->audioDeviceIOCallback ((const float**) inBuffers,
|
||||
numActiveInputChans,
|
||||
outBuffers,
|
||||
numActiveOutputChans,
|
||||
samps);
|
||||
currentCallback->audioDeviceIOCallback ((const float**) inBuffers, numActiveInputChans,
|
||||
outBuffers, numActiveOutputChans, samps);
|
||||
|
||||
for (i = 0; i < numActiveOutputChans; ++i)
|
||||
{
|
||||
float* const src = outBuffers[i];
|
||||
|
||||
jassert (src != 0);
|
||||
|
||||
char* const dst = (char*) (infos [numActiveInputChans + i].buffers[bi]);
|
||||
|
|
@ -253757,7 +253695,8 @@ public:
|
|||
width (0),
|
||||
height (0),
|
||||
activeUsers (0),
|
||||
recordNextFrameTime (false)
|
||||
recordNextFrameTime (false),
|
||||
previewMaxFPS (60)
|
||||
{
|
||||
HRESULT hr = graphBuilder.CoCreateInstance (CLSID_FilterGraph);
|
||||
if (FAILED (hr))
|
||||
|
|
@ -253888,6 +253827,11 @@ public:
|
|||
mediaControl->Stop();
|
||||
}
|
||||
|
||||
int getPreviewMaxFPS() const
|
||||
{
|
||||
return previewMaxFPS;
|
||||
}
|
||||
|
||||
void handleFrame (double /*time*/, BYTE* buffer, long /*bufferSize*/)
|
||||
{
|
||||
if (recordNextFrameTime)
|
||||
|
|
@ -253958,13 +253902,14 @@ public:
|
|||
g.drawImage (activeImage, rx, ry, rw, rh, 0, 0, width, height);
|
||||
}
|
||||
|
||||
bool createFileCaptureFilter (const File& file)
|
||||
bool createFileCaptureFilter (const File& file, int quality)
|
||||
{
|
||||
removeFileCaptureFilter();
|
||||
file.deleteFile();
|
||||
mediaControl->Stop();
|
||||
firstRecordedTime = Time();
|
||||
recordNextFrameTime = true;
|
||||
previewMaxFPS = 60;
|
||||
|
||||
HRESULT hr = asfWriter.CoCreateInstance (CLSID_WMAsfWriter);
|
||||
|
||||
|
|
@ -253990,17 +253935,30 @@ public:
|
|||
hr = WMCreateProfileManager (profileManager.resetAndGetPointerAddress());
|
||||
|
||||
// This gibberish is the DirectShow profile for a video-only wmv file.
|
||||
String prof ("<profile version=\"589824\" storageformat=\"1\" name=\"Quality\" description=\"Quality type for output.\"><streamconfig "
|
||||
"majortype=\"{73646976-0000-0010-8000-00AA00389B71}\" streamnumber=\"1\" streamname=\"Video Stream\" inputname=\"Video409\" bitrate=\"894960\" "
|
||||
"bufferwindow=\"0\" reliabletransport=\"1\" decodercomplexity=\"AU\" rfc1766langid=\"en-us\"><videomediaprops maxkeyframespacing=\"50000000\" quality=\"90\"/>"
|
||||
"<wmmediatype subtype=\"{33564D57-0000-0010-8000-00AA00389B71}\" bfixedsizesamples=\"0\" btemporalcompression=\"1\" lsamplesize=\"0\"> <videoinfoheader "
|
||||
"dwbitrate=\"894960\" dwbiterrorrate=\"0\" avgtimeperframe=\"100000\"><rcsource left=\"0\" top=\"0\" right=\"$WIDTH\" bottom=\"$HEIGHT\"/> <rctarget "
|
||||
"left=\"0\" top=\"0\" right=\"$WIDTH\" bottom=\"$HEIGHT\"/> <bitmapinfoheader biwidth=\"$WIDTH\" biheight=\"$HEIGHT\" biplanes=\"1\" bibitcount=\"24\" "
|
||||
"bicompression=\"WMV3\" bisizeimage=\"0\" bixpelspermeter=\"0\" biypelspermeter=\"0\" biclrused=\"0\" biclrimportant=\"0\"/> "
|
||||
"</videoinfoheader></wmmediatype></streamconfig></profile>");
|
||||
String prof ("<profile version=\"589824\" storageformat=\"1\" name=\"Quality\" description=\"Quality type for output.\">"
|
||||
" <streamconfig majortype=\"{73646976-0000-0010-8000-00AA00389B71}\" streamnumber=\"1\""
|
||||
" streamname=\"Video Stream\" inputname=\"Video409\" bitrate=\"894960\""
|
||||
" bufferwindow=\"0\" reliabletransport=\"1\" decodercomplexity=\"AU\" rfc1766langid=\"en-us\">"
|
||||
" <videomediaprops maxkeyframespacing=\"50000000\" quality=\"90\"/>"
|
||||
" <wmmediatype subtype=\"{33564D57-0000-0010-8000-00AA00389B71}\" bfixedsizesamples=\"0\""
|
||||
" btemporalcompression=\"1\" lsamplesize=\"0\">"
|
||||
" <videoinfoheader dwbitrate=\"894960\" dwbiterrorrate=\"0\" avgtimeperframe=\"$AVGTIMEPERFRAME\">"
|
||||
" <rcsource left=\"0\" top=\"0\" right=\"$WIDTH\" bottom=\"$HEIGHT\"/>"
|
||||
" <rctarget left=\"0\" top=\"0\" right=\"$WIDTH\" bottom=\"$HEIGHT\"/>"
|
||||
" <bitmapinfoheader biwidth=\"$WIDTH\" biheight=\"$HEIGHT\" biplanes=\"1\" bibitcount=\"24\""
|
||||
" bicompression=\"WMV3\" bisizeimage=\"0\" bixpelspermeter=\"0\" biypelspermeter=\"0\""
|
||||
" biclrused=\"0\" biclrimportant=\"0\"/>"
|
||||
" </videoinfoheader>"
|
||||
" </wmmediatype>"
|
||||
" </streamconfig>"
|
||||
"</profile>");
|
||||
|
||||
const int fps[] = { 10, 15, 30 };
|
||||
const int maxFramesPerSecond = fps [quality % numElementsInArray (fps)];
|
||||
|
||||
prof = prof.replace ("$WIDTH", String (width))
|
||||
.replace ("$HEIGHT", String (height));
|
||||
.replace ("$HEIGHT", String (height))
|
||||
.replace ("$AVGTIMEPERFRAME", String (10000000 / maxFramesPerSecond));
|
||||
|
||||
ComSmartPtr <IWMProfile> currentProfile;
|
||||
hr = profileManager->LoadProfileByData ((const WCHAR*) prof, currentProfile.resetAndGetPointerAddress());
|
||||
|
|
@ -254018,6 +253976,7 @@ public:
|
|||
&& ok && activeUsers > 0
|
||||
&& SUCCEEDED (mediaControl->Run()))
|
||||
{
|
||||
previewMaxFPS = (quality < 2) ? 15 : 25; // throttle back the preview comps to try to leave the cpu free for encoding
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -254047,6 +254006,8 @@ public:
|
|||
|
||||
if (ok && activeUsers > 0)
|
||||
mediaControl->Run();
|
||||
|
||||
previewMaxFPS = 60;
|
||||
}
|
||||
|
||||
void addListener (CameraDevice::Listener* listenerToAdd)
|
||||
|
|
@ -254086,7 +254047,7 @@ public:
|
|||
{
|
||||
public:
|
||||
DShowCaptureViewerComp (DShowCameraDeviceInteral* const owner_)
|
||||
: owner (owner_)
|
||||
: owner (owner_), maxFPS (15), lastRepaintTime (0)
|
||||
{
|
||||
setOpaque (true);
|
||||
owner->addChangeListener (this);
|
||||
|
|
@ -254123,11 +254084,22 @@ public:
|
|||
|
||||
void changeListenerCallback (void*)
|
||||
{
|
||||
repaint();
|
||||
const int64 now = Time::currentTimeMillis();
|
||||
|
||||
if (now >= lastRepaintTime + (1000 / maxFPS))
|
||||
{
|
||||
lastRepaintTime = now;
|
||||
repaint();
|
||||
|
||||
if (owner != 0)
|
||||
maxFPS = owner->getPreviewMaxFPS();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
DShowCameraDeviceInteral* owner;
|
||||
int maxFPS;
|
||||
int64 lastRepaintTime;
|
||||
};
|
||||
|
||||
bool ok;
|
||||
|
|
@ -254157,6 +254129,7 @@ private:
|
|||
Image activeImage;
|
||||
|
||||
bool recordNextFrameTime;
|
||||
int previewMaxFPS;
|
||||
|
||||
void getVideoSizes (IAMStreamConfig* const streamConfig)
|
||||
{
|
||||
|
|
@ -254384,11 +254357,12 @@ const String CameraDevice::getFileExtension()
|
|||
|
||||
void CameraDevice::startRecordingToFile (const File& file, int quality)
|
||||
{
|
||||
jassert (quality >= 0 && quality <= 2);
|
||||
stopRecording();
|
||||
|
||||
DShowCameraDeviceInteral* const d = (DShowCameraDeviceInteral*) internal;
|
||||
d->addUser();
|
||||
isRecording = d->createFileCaptureFilter (file);
|
||||
isRecording = d->createFileCaptureFilter (file, quality);
|
||||
}
|
||||
|
||||
const Time CameraDevice::getTimeOfFirstRecordedFrame() const
|
||||
|
|
@ -265301,7 +265275,7 @@ bool File::isHidden() const
|
|||
static const String getIOSSystemLocation (NSSearchPathDirectory type)
|
||||
{
|
||||
return nsStringToJuce ([NSSearchPathForDirectoriesInDomains (type, NSUserDomainMask, YES)
|
||||
objectAtIndex:0]);
|
||||
objectAtIndex: 0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -276241,17 +276215,12 @@ static NSArray* findDiskBurnerDevices()
|
|||
NSMutableArray* results = [NSMutableArray array];
|
||||
NSArray* devs = [DRDevice devices];
|
||||
|
||||
if (devs != 0)
|
||||
for (int i = 0; i < [devs count]; ++i)
|
||||
{
|
||||
int num = [devs count];
|
||||
int i;
|
||||
for (i = 0; i < num; ++i)
|
||||
{
|
||||
NSDictionary* dic = [[devs objectAtIndex: i] info];
|
||||
NSString* name = [dic valueForKey: DRDeviceProductNameKey];
|
||||
if (name != nil)
|
||||
[results addObject: name];
|
||||
}
|
||||
NSDictionary* dic = [[devs objectAtIndex: i] info];
|
||||
NSString* name = [dic valueForKey: DRDeviceProductNameKey];
|
||||
if (name != nil)
|
||||
[results addObject: name];
|
||||
}
|
||||
|
||||
return results;
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@
|
|||
*/
|
||||
#define JUCE_MAJOR_VERSION 1
|
||||
#define JUCE_MINOR_VERSION 52
|
||||
#define JUCE_BUILDNUMBER 77
|
||||
#define JUCE_BUILDNUMBER 78
|
||||
|
||||
/** Current Juce version number.
|
||||
|
||||
|
|
@ -1123,18 +1123,19 @@ inline void swapVariables (Type& variable1, Type& variable2)
|
|||
int numElements = numElementsInArray (myArray) // returns 3
|
||||
@endcode
|
||||
*/
|
||||
template <typename Type>
|
||||
inline int numElementsInArray (Type& array)
|
||||
template <typename Type, int N>
|
||||
inline int numElementsInArray (Type (&array)[N])
|
||||
{
|
||||
(void) array; // (required to avoid a spurious warning in MS compilers)
|
||||
return static_cast<int> (sizeof (array) / sizeof (0[array]));
|
||||
sizeof (0[array]); // This line should cause an error if you pass an object with a user-defined subscript operator
|
||||
return N;
|
||||
}
|
||||
|
||||
// Some useful maths functions that aren't always present with all compilers and build settings.
|
||||
|
||||
/** Using juce_hypot and juce_hypotf is easier than dealing with all the different
|
||||
versions of these functions of various platforms and compilers. */
|
||||
inline double juce_hypot (double a, double b)
|
||||
inline double juce_hypot (double a, double b) throw()
|
||||
{
|
||||
#if JUCE_WINDOWS
|
||||
return _hypot (a, b);
|
||||
|
|
@ -3665,9 +3666,7 @@ static void sortArray (ElementComparator& comparator,
|
|||
{
|
||||
if (comparator.compareElements (array[i], array [i + 1]) > 0)
|
||||
{
|
||||
const ElementType temp = array [i];
|
||||
array [i] = array[i + 1];
|
||||
array [i + 1] = temp;
|
||||
swapVariables (array[i], array[i + 1]);
|
||||
|
||||
if (i > firstElement)
|
||||
i -= 2;
|
||||
|
|
@ -3695,19 +3694,14 @@ static void sortArray (ElementComparator& comparator,
|
|||
if (comparator.compareElements (array[k], array [maxIndex]) > 0)
|
||||
maxIndex = k;
|
||||
|
||||
const ElementType temp = array [maxIndex];
|
||||
array [maxIndex] = array[j];
|
||||
array [j] = temp;
|
||||
|
||||
swapVariables (array[j], array[maxIndex]);
|
||||
--j;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const int mid = firstElement + (size >> 1);
|
||||
ElementType temp = array [mid];
|
||||
array [mid] = array [firstElement];
|
||||
array [firstElement] = temp;
|
||||
swapVariables (array[mid], array[firstElement]);
|
||||
|
||||
int i = firstElement;
|
||||
int j = lastElement + 1;
|
||||
|
|
@ -3725,14 +3719,10 @@ static void sortArray (ElementComparator& comparator,
|
|||
if (j < i)
|
||||
break;
|
||||
|
||||
temp = array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = temp;
|
||||
swapVariables (array[i], array[j]);
|
||||
}
|
||||
|
||||
temp = array [firstElement];
|
||||
array [firstElement] = array[j];
|
||||
array [j] = temp;
|
||||
swapVariables (array[j], array[firstElement]);
|
||||
|
||||
if (j - 1 - firstElement >= lastElement - i)
|
||||
{
|
||||
|
|
@ -13897,22 +13887,21 @@ public:
|
|||
To improve performance, the compareElements() method can be declared as static or const.
|
||||
|
||||
@param comparator the comparator to use for comparing elements.
|
||||
@param retainOrderOfEquivalentItems if this is true, then items
|
||||
which the comparator says are equivalent will be
|
||||
kept in the order in which they currently appear
|
||||
in the array. This is slower to perform, but may
|
||||
be important in some cases. If it's false, a faster
|
||||
algorithm is used, but equivalent elements may be
|
||||
rearranged.
|
||||
@param undoManager optional UndoManager for storing the changes
|
||||
@param retainOrderOfEquivalentItems if this is true, then items which the comparator says are
|
||||
equivalent will be kept in the order in which they currently appear in the array.
|
||||
This is slower to perform, but may be important in some cases. If it's false, a
|
||||
faster algorithm is used, but equivalent elements may be rearranged.
|
||||
*/
|
||||
template <typename ElementComparator>
|
||||
void sort (ElementComparator& comparator, const bool retainOrderOfEquivalentItems = false)
|
||||
void sort (ElementComparator& comparator, UndoManager* undoManager, bool retainOrderOfEquivalentItems)
|
||||
{
|
||||
if (object != 0)
|
||||
{
|
||||
ReferenceCountedArray <SharedObject> sortedList (object->children);
|
||||
ComparatorAdapter <ElementComparator> adapter (comparator);
|
||||
object->children.sort (adapter, retainOrderOfEquivalentItems);
|
||||
object->sendChildChangeMessage();
|
||||
sortedList.sort (adapter, retainOrderOfEquivalentItems);
|
||||
object->reorderChildren (sortedList, undoManager);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -13964,6 +13953,7 @@ private:
|
|||
void removeChild (int childIndex, UndoManager*);
|
||||
void removeAllChildren (UndoManager*);
|
||||
void moveChild (int currentIndex, int newIndex, UndoManager*);
|
||||
void reorderChildren (const ReferenceCountedArray <SharedObject>& newOrder, UndoManager*);
|
||||
bool isEquivalentTo (const SharedObject& other) const;
|
||||
XmlElement* createXml() const;
|
||||
|
||||
|
|
@ -24392,14 +24382,8 @@ public:
|
|||
/** Returns the transform that should be applied to these source co-ordinates to fit them
|
||||
into the destination rectangle using the current flags.
|
||||
*/
|
||||
const AffineTransform getTransformToFit (float sourceX,
|
||||
float sourceY,
|
||||
float sourceW,
|
||||
float sourceH,
|
||||
float destinationX,
|
||||
float destinationY,
|
||||
float destinationW,
|
||||
float destinationH) const throw();
|
||||
const AffineTransform getTransformToFit (const Rectangle<float>& source,
|
||||
const Rectangle<float>& destination) const throw();
|
||||
|
||||
private:
|
||||
|
||||
|
|
@ -43224,6 +43208,9 @@ private:
|
|||
just call the post() method to send them, and when they arrive, your
|
||||
messageCallback() method will automatically be invoked.
|
||||
|
||||
Always create an instance of a CallbackMessage on the heap, as it will be
|
||||
deleted automatically after the message has been delivered.
|
||||
|
||||
@see MessageListener, MessageManager, ActionListener, ChangeListener
|
||||
*/
|
||||
class JUCE_API CallbackMessage : public Message
|
||||
|
|
@ -44527,19 +44514,13 @@ public:
|
|||
and can either be made as big as possible, or just reduced to fit.
|
||||
|
||||
@param g the graphics context to render onto
|
||||
@param destX top-left of the target rectangle to fit it into
|
||||
@param destY top-left of the target rectangle to fit it into
|
||||
@param destWidth size of the target rectangle to fit the image into
|
||||
@param destHeight size of the target rectangle to fit the image into
|
||||
@param destArea the target rectangle to fit the drawable into
|
||||
@param placement defines the alignment and rescaling to use to fit
|
||||
this object within the target rectangle.
|
||||
@param opacity the opacity to use, in the range 0 to 1.0
|
||||
*/
|
||||
void drawWithin (Graphics& g,
|
||||
int destX,
|
||||
int destY,
|
||||
int destWidth,
|
||||
int destHeight,
|
||||
const Rectangle<float>& destArea,
|
||||
const RectanglePlacement& placement,
|
||||
float opacity) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -172,11 +172,12 @@ inline void swapVariables (Type& variable1, Type& variable2)
|
|||
int numElements = numElementsInArray (myArray) // returns 3
|
||||
@endcode
|
||||
*/
|
||||
template <typename Type>
|
||||
inline int numElementsInArray (Type& array)
|
||||
template <typename Type, int N>
|
||||
inline int numElementsInArray (Type (&array)[N])
|
||||
{
|
||||
(void) array; // (required to avoid a spurious warning in MS compilers)
|
||||
return static_cast<int> (sizeof (array) / sizeof (0[array]));
|
||||
sizeof (0[array]); // This line should cause an error if you pass an object with a user-defined subscript operator
|
||||
return N;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -184,7 +185,7 @@ inline int numElementsInArray (Type& array)
|
|||
|
||||
/** Using juce_hypot and juce_hypotf is easier than dealing with all the different
|
||||
versions of these functions of various platforms and compilers. */
|
||||
inline double juce_hypot (double a, double b)
|
||||
inline double juce_hypot (double a, double b) throw()
|
||||
{
|
||||
#if JUCE_WINDOWS
|
||||
return _hypot (a, b);
|
||||
|
|
|
|||
|
|
@ -69,22 +69,12 @@ void Drawable::drawAt (Graphics& g, const float x, const float y, const float op
|
|||
}
|
||||
|
||||
void Drawable::drawWithin (Graphics& g,
|
||||
const int destX,
|
||||
const int destY,
|
||||
const int destW,
|
||||
const int destH,
|
||||
const Rectangle<float>& destArea,
|
||||
const RectanglePlacement& placement,
|
||||
const float opacity) const
|
||||
{
|
||||
if (destW > 0 && destH > 0)
|
||||
{
|
||||
Rectangle<float> bounds (getBounds());
|
||||
|
||||
draw (g, opacity,
|
||||
placement.getTransformToFit (bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(),
|
||||
(float) destX, (float) destY,
|
||||
(float) destW, (float) destH));
|
||||
}
|
||||
if (! destArea.isEmpty())
|
||||
draw (g, opacity, placement.getTransformToFit (getBounds(), destArea));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -38,8 +38,7 @@
|
|||
#define log(a) {}
|
||||
#endif
|
||||
|
||||
#define JUCE_ASIOCALLBACK // should probably use this to define the callback type, but
|
||||
// the asio header doesn't actually specify a calling convention for the functions..
|
||||
#define JUCE_ASIOCALLBACK __cdecl
|
||||
|
||||
//==============================================================================
|
||||
#if ASIO_DEBUGGING
|
||||
|
|
@ -146,40 +145,15 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
const StringArray getOutputChannelNames()
|
||||
{
|
||||
return outputChannelNames;
|
||||
}
|
||||
const StringArray getOutputChannelNames() { return outputChannelNames; }
|
||||
const StringArray getInputChannelNames() { return inputChannelNames; }
|
||||
|
||||
const StringArray getInputChannelNames()
|
||||
{
|
||||
return inputChannelNames;
|
||||
}
|
||||
int getNumSampleRates() { return sampleRates.size(); }
|
||||
double getSampleRate (int index) { return sampleRates [index]; }
|
||||
|
||||
int getNumSampleRates()
|
||||
{
|
||||
return sampleRates.size();
|
||||
}
|
||||
|
||||
double getSampleRate (int index)
|
||||
{
|
||||
return sampleRates [index];
|
||||
}
|
||||
|
||||
int getNumBufferSizesAvailable()
|
||||
{
|
||||
return bufferSizes.size();
|
||||
}
|
||||
|
||||
int getBufferSizeSamples (int index)
|
||||
{
|
||||
return bufferSizes [index];
|
||||
}
|
||||
|
||||
int getDefaultBufferSize()
|
||||
{
|
||||
return preferredSize;
|
||||
}
|
||||
int getNumBufferSizesAvailable() { return bufferSizes.size(); }
|
||||
int getBufferSizeSamples (int index) { return bufferSizes [index]; }
|
||||
int getDefaultBufferSize() { return preferredSize; }
|
||||
|
||||
const String open (const BigInteger& inputChannels,
|
||||
const BigInteger& outputChannels,
|
||||
|
|
@ -633,45 +607,18 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
bool isOpen()
|
||||
{
|
||||
return isOpen_ || insideControlPanelModalLoop;
|
||||
}
|
||||
bool isOpen() { return isOpen_ || insideControlPanelModalLoop; }
|
||||
bool isPlaying() { return isASIOOpen && (currentCallback != 0); }
|
||||
|
||||
int getCurrentBufferSizeSamples()
|
||||
{
|
||||
return currentBlockSizeSamples;
|
||||
}
|
||||
int getCurrentBufferSizeSamples() { return currentBlockSizeSamples; }
|
||||
double getCurrentSampleRate() { return currentSampleRate; }
|
||||
int getCurrentBitDepth() { return currentBitDepth; }
|
||||
|
||||
double getCurrentSampleRate()
|
||||
{
|
||||
return currentSampleRate;
|
||||
}
|
||||
const BigInteger getActiveOutputChannels() const { return currentChansOut; }
|
||||
const BigInteger getActiveInputChannels() const { return currentChansIn; }
|
||||
|
||||
const BigInteger getActiveOutputChannels() const
|
||||
{
|
||||
return currentChansOut;
|
||||
}
|
||||
|
||||
const BigInteger getActiveInputChannels() const
|
||||
{
|
||||
return currentChansIn;
|
||||
}
|
||||
|
||||
int getCurrentBitDepth()
|
||||
{
|
||||
return currentBitDepth;
|
||||
}
|
||||
|
||||
int getOutputLatencyInSamples()
|
||||
{
|
||||
return outputLatency + currentBlockSizeSamples / 4;
|
||||
}
|
||||
|
||||
int getInputLatencyInSamples()
|
||||
{
|
||||
return inputLatency + currentBlockSizeSamples / 4;
|
||||
}
|
||||
int getOutputLatencyInSamples() { return outputLatency + currentBlockSizeSamples / 4; }
|
||||
int getInputLatencyInSamples() { return inputLatency + currentBlockSizeSamples / 4; }
|
||||
|
||||
void start (AudioIODeviceCallback* callback)
|
||||
{
|
||||
|
|
@ -697,20 +644,8 @@ public:
|
|||
lastCallback->audioDeviceStopped();
|
||||
}
|
||||
|
||||
bool isPlaying()
|
||||
{
|
||||
return isASIOOpen && (currentCallback != 0);
|
||||
}
|
||||
|
||||
const String getLastError()
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
bool hasControlPanel() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
const String getLastError() { return error; }
|
||||
bool hasControlPanel() const { return true; }
|
||||
|
||||
bool showControlPanel()
|
||||
{
|
||||
|
|
@ -840,7 +775,6 @@ private:
|
|||
bool volatile insideControlPanelModalLoop;
|
||||
bool volatile shouldUsePreferredSize;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
void removeCurrentDriver()
|
||||
{
|
||||
|
|
@ -1242,7 +1176,6 @@ private:
|
|||
for (i = 0; i < numActiveInputChans; ++i)
|
||||
{
|
||||
float* const dst = inBuffers[i];
|
||||
|
||||
jassert (dst != 0);
|
||||
|
||||
const char* const src = (const char*) (infos[i].buffers[bi]);
|
||||
|
|
@ -1279,16 +1212,12 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
currentCallback->audioDeviceIOCallback ((const float**) inBuffers,
|
||||
numActiveInputChans,
|
||||
outBuffers,
|
||||
numActiveOutputChans,
|
||||
samps);
|
||||
currentCallback->audioDeviceIOCallback ((const float**) inBuffers, numActiveInputChans,
|
||||
outBuffers, numActiveOutputChans, samps);
|
||||
|
||||
for (i = 0; i < numActiveOutputChans; ++i)
|
||||
{
|
||||
float* const src = outBuffers[i];
|
||||
|
||||
jassert (src != 0);
|
||||
|
||||
char* const dst = (char*) (infos [numActiveInputChans + i].buffers[bi]);
|
||||
|
|
|
|||
|
|
@ -45,7 +45,8 @@ public:
|
|||
width (0),
|
||||
height (0),
|
||||
activeUsers (0),
|
||||
recordNextFrameTime (false)
|
||||
recordNextFrameTime (false),
|
||||
previewMaxFPS (60)
|
||||
{
|
||||
HRESULT hr = graphBuilder.CoCreateInstance (CLSID_FilterGraph);
|
||||
if (FAILED (hr))
|
||||
|
|
@ -176,6 +177,11 @@ public:
|
|||
mediaControl->Stop();
|
||||
}
|
||||
|
||||
int getPreviewMaxFPS() const
|
||||
{
|
||||
return previewMaxFPS;
|
||||
}
|
||||
|
||||
void handleFrame (double /*time*/, BYTE* buffer, long /*bufferSize*/)
|
||||
{
|
||||
if (recordNextFrameTime)
|
||||
|
|
@ -246,13 +252,14 @@ public:
|
|||
g.drawImage (activeImage, rx, ry, rw, rh, 0, 0, width, height);
|
||||
}
|
||||
|
||||
bool createFileCaptureFilter (const File& file)
|
||||
bool createFileCaptureFilter (const File& file, int quality)
|
||||
{
|
||||
removeFileCaptureFilter();
|
||||
file.deleteFile();
|
||||
mediaControl->Stop();
|
||||
firstRecordedTime = Time();
|
||||
recordNextFrameTime = true;
|
||||
previewMaxFPS = 60;
|
||||
|
||||
HRESULT hr = asfWriter.CoCreateInstance (CLSID_WMAsfWriter);
|
||||
|
||||
|
|
@ -278,17 +285,30 @@ public:
|
|||
hr = WMCreateProfileManager (profileManager.resetAndGetPointerAddress());
|
||||
|
||||
// This gibberish is the DirectShow profile for a video-only wmv file.
|
||||
String prof ("<profile version=\"589824\" storageformat=\"1\" name=\"Quality\" description=\"Quality type for output.\"><streamconfig "
|
||||
"majortype=\"{73646976-0000-0010-8000-00AA00389B71}\" streamnumber=\"1\" streamname=\"Video Stream\" inputname=\"Video409\" bitrate=\"894960\" "
|
||||
"bufferwindow=\"0\" reliabletransport=\"1\" decodercomplexity=\"AU\" rfc1766langid=\"en-us\"><videomediaprops maxkeyframespacing=\"50000000\" quality=\"90\"/>"
|
||||
"<wmmediatype subtype=\"{33564D57-0000-0010-8000-00AA00389B71}\" bfixedsizesamples=\"0\" btemporalcompression=\"1\" lsamplesize=\"0\"> <videoinfoheader "
|
||||
"dwbitrate=\"894960\" dwbiterrorrate=\"0\" avgtimeperframe=\"100000\"><rcsource left=\"0\" top=\"0\" right=\"$WIDTH\" bottom=\"$HEIGHT\"/> <rctarget "
|
||||
"left=\"0\" top=\"0\" right=\"$WIDTH\" bottom=\"$HEIGHT\"/> <bitmapinfoheader biwidth=\"$WIDTH\" biheight=\"$HEIGHT\" biplanes=\"1\" bibitcount=\"24\" "
|
||||
"bicompression=\"WMV3\" bisizeimage=\"0\" bixpelspermeter=\"0\" biypelspermeter=\"0\" biclrused=\"0\" biclrimportant=\"0\"/> "
|
||||
"</videoinfoheader></wmmediatype></streamconfig></profile>");
|
||||
String prof ("<profile version=\"589824\" storageformat=\"1\" name=\"Quality\" description=\"Quality type for output.\">"
|
||||
" <streamconfig majortype=\"{73646976-0000-0010-8000-00AA00389B71}\" streamnumber=\"1\""
|
||||
" streamname=\"Video Stream\" inputname=\"Video409\" bitrate=\"894960\""
|
||||
" bufferwindow=\"0\" reliabletransport=\"1\" decodercomplexity=\"AU\" rfc1766langid=\"en-us\">"
|
||||
" <videomediaprops maxkeyframespacing=\"50000000\" quality=\"90\"/>"
|
||||
" <wmmediatype subtype=\"{33564D57-0000-0010-8000-00AA00389B71}\" bfixedsizesamples=\"0\""
|
||||
" btemporalcompression=\"1\" lsamplesize=\"0\">"
|
||||
" <videoinfoheader dwbitrate=\"894960\" dwbiterrorrate=\"0\" avgtimeperframe=\"$AVGTIMEPERFRAME\">"
|
||||
" <rcsource left=\"0\" top=\"0\" right=\"$WIDTH\" bottom=\"$HEIGHT\"/>"
|
||||
" <rctarget left=\"0\" top=\"0\" right=\"$WIDTH\" bottom=\"$HEIGHT\"/>"
|
||||
" <bitmapinfoheader biwidth=\"$WIDTH\" biheight=\"$HEIGHT\" biplanes=\"1\" bibitcount=\"24\""
|
||||
" bicompression=\"WMV3\" bisizeimage=\"0\" bixpelspermeter=\"0\" biypelspermeter=\"0\""
|
||||
" biclrused=\"0\" biclrimportant=\"0\"/>"
|
||||
" </videoinfoheader>"
|
||||
" </wmmediatype>"
|
||||
" </streamconfig>"
|
||||
"</profile>");
|
||||
|
||||
const int fps[] = { 10, 15, 30 };
|
||||
const int maxFramesPerSecond = fps [quality % numElementsInArray (fps)];
|
||||
|
||||
prof = prof.replace ("$WIDTH", String (width))
|
||||
.replace ("$HEIGHT", String (height));
|
||||
.replace ("$HEIGHT", String (height))
|
||||
.replace ("$AVGTIMEPERFRAME", String (10000000 / maxFramesPerSecond));
|
||||
|
||||
ComSmartPtr <IWMProfile> currentProfile;
|
||||
hr = profileManager->LoadProfileByData ((const WCHAR*) prof, currentProfile.resetAndGetPointerAddress());
|
||||
|
|
@ -306,6 +326,7 @@ public:
|
|||
&& ok && activeUsers > 0
|
||||
&& SUCCEEDED (mediaControl->Run()))
|
||||
{
|
||||
previewMaxFPS = (quality < 2) ? 15 : 25; // throttle back the preview comps to try to leave the cpu free for encoding
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -335,6 +356,8 @@ public:
|
|||
|
||||
if (ok && activeUsers > 0)
|
||||
mediaControl->Run();
|
||||
|
||||
previewMaxFPS = 60;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -377,7 +400,7 @@ public:
|
|||
{
|
||||
public:
|
||||
DShowCaptureViewerComp (DShowCameraDeviceInteral* const owner_)
|
||||
: owner (owner_)
|
||||
: owner (owner_), maxFPS (15), lastRepaintTime (0)
|
||||
{
|
||||
setOpaque (true);
|
||||
owner->addChangeListener (this);
|
||||
|
|
@ -414,11 +437,22 @@ public:
|
|||
|
||||
void changeListenerCallback (void*)
|
||||
{
|
||||
repaint();
|
||||
const int64 now = Time::currentTimeMillis();
|
||||
|
||||
if (now >= lastRepaintTime + (1000 / maxFPS))
|
||||
{
|
||||
lastRepaintTime = now;
|
||||
repaint();
|
||||
|
||||
if (owner != 0)
|
||||
maxFPS = owner->getPreviewMaxFPS();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
DShowCameraDeviceInteral* owner;
|
||||
int maxFPS;
|
||||
int64 lastRepaintTime;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -449,6 +483,7 @@ private:
|
|||
Image activeImage;
|
||||
|
||||
bool recordNextFrameTime;
|
||||
int previewMaxFPS;
|
||||
|
||||
void getVideoSizes (IAMStreamConfig* const streamConfig)
|
||||
{
|
||||
|
|
@ -681,11 +716,12 @@ const String CameraDevice::getFileExtension()
|
|||
|
||||
void CameraDevice::startRecordingToFile (const File& file, int quality)
|
||||
{
|
||||
jassert (quality >= 0 && quality <= 2);
|
||||
stopRecording();
|
||||
|
||||
DShowCameraDeviceInteral* const d = (DShowCameraDeviceInteral*) internal;
|
||||
d->addUser();
|
||||
isRecording = d->createFileCaptureFilter (file);
|
||||
isRecording = d->createFileCaptureFilter (file, quality);
|
||||
}
|
||||
|
||||
const Time CameraDevice::getTimeOfFirstRecordedFrame() const
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue