diff --git a/lib/native/windows-64/jndirectshow.dll b/lib/native/windows-64/jndirectshow.dll index 06e7a87b0f5e032b010c5ecfafa7c18e87f22e25..3e5e5faa38e46728db0df559cbcb28edb0a4d840 100644 Binary files a/lib/native/windows-64/jndirectshow.dll and b/lib/native/windows-64/jndirectshow.dll differ diff --git a/lib/native/windows/jndirectshow.dll b/lib/native/windows/jndirectshow.dll index 3326eec6925c12f6feb090d8b69682b4c8f543a3..594fcdb4dc4b0e0e438b45e3f634daddbc4e631f 100644 Binary files a/lib/native/windows/jndirectshow.dll and b/lib/native/windows/jndirectshow.dll differ diff --git a/src/native/windows/directshow/DSCaptureDevice.cpp b/src/native/windows/directshow/DSCaptureDevice.cpp index 2ee47577bf9e38cd89ec81ca1008ee7f33ea8911..d88899c860094fba739a0f7ef302870873e09993 100644 --- a/src/native/windows/directshow/DSCaptureDevice.cpp +++ b/src/native/windows/directshow/DSCaptureDevice.cpp @@ -63,6 +63,26 @@ STDMETHODIMP_(ULONG) DSGrabberCallback::Release() return 1; } +static void +_DeleteMediaType(AM_MEDIA_TYPE *mt) +{ + if (mt) + { + if (mt->cbFormat && mt->pbFormat) + { + ::CoTaskMemFree((LPVOID) mt->pbFormat); + mt->cbFormat = 0; + mt->pbFormat = NULL; + } + if (mt->pUnk) + { + mt->pUnk->Release(); + mt->pUnk = NULL; + } + ::CoTaskMemFree(mt); + } +} + DSCaptureDevice::DSCaptureDevice(const WCHAR* name) { if(name) @@ -124,84 +144,89 @@ const WCHAR* DSCaptureDevice::getName() const return m_name; } -bool DSCaptureDevice::setFormat(const DSFormat& format) +HRESULT DSCaptureDevice::setFormat(const DSFormat& format) { - HRESULT ret; + HRESULT hr; IAMStreamConfig* streamConfig = NULL; - AM_MEDIA_TYPE* mediaType = NULL; /* get the right interface to change capture settings */ - ret = m_captureGraphBuilder->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, - m_srcFilter, IID_IAMStreamConfig, (void**)&streamConfig); - - if(!FAILED(ret)) + hr + = m_captureGraphBuilder->FindInterface( + &PIN_CATEGORY_CAPTURE, + &MEDIATYPE_Video, + m_srcFilter, + IID_IAMStreamConfig, + (void**) &streamConfig); + if(SUCCEEDED(hr)) { - size_t bitCount = 0; int nb = 0; int size = 0; - BYTE* allocBytes = NULL; - AM_MEDIA_TYPE* mt; - bool found = false; + AM_MEDIA_TYPE* mediaType = NULL; + size_t bitCount = 0; - streamConfig->GetNumberOfCapabilities(&nb, &size); - allocBytes = new BYTE[size]; - - for(int i = 0 ; i < nb ; i++) + hr = streamConfig->GetNumberOfCapabilities(&nb, &size); + if (SUCCEEDED(hr) && nb) { - if(streamConfig->GetStreamCaps(i, &mt, allocBytes) == S_OK) - { - VIDEOINFOHEADER* hdr = (VIDEOINFOHEADER*)mt->pbFormat; + BYTE* scc = new BYTE[size]; - if(hdr) + if (scc) + { + for (int i = 0 ; i < nb ; i++) { - if((long)format.height == hdr->bmiHeader.biHeight && - (long)format.width == hdr->bmiHeader.biWidth) + AM_MEDIA_TYPE* mt; + + if (streamConfig->GetStreamCaps(i, &mt, scc) == S_OK) { - mediaType = mt; - if(format.pixelFormat == MEDIASUBTYPE_ARGB32.Data1 || - format.pixelFormat == MEDIASUBTYPE_RGB32.Data1) - { - bitCount = 32; - } - else if(format.pixelFormat == MEDIASUBTYPE_RGB24.Data1) + VIDEOINFOHEADER* hdr = (VIDEOINFOHEADER*) mt->pbFormat; + + if (hdr + && ((long) format.height + == hdr->bmiHeader.biHeight) + && ((long) format.width + == hdr->bmiHeader.biWidth)) { - bitCount = 24; + mediaType = mt; + if ((format.pixelFormat + == MEDIASUBTYPE_ARGB32.Data1) + || (format.pixelFormat + == MEDIASUBTYPE_RGB32.Data1)) + bitCount = 32; + else if (format.pixelFormat + == MEDIASUBTYPE_RGB24.Data1) + bitCount = 24; + else + bitCount = hdr->bmiHeader.biBitCount; + break; } else - { - bitCount = hdr->bmiHeader.biBitCount; - } - - found = true; - break; + _DeleteMediaType(mt); } } + + delete[] scc; } + else + hr = E_OUTOFMEMORY; } - if(found) + if (mediaType) { - ret = streamConfig->SetFormat(mediaType); - - if(FAILED(ret)) - { - fprintf(stderr, "Failed to set format\n"); - fflush(stderr); - } - else + hr = streamConfig->SetFormat(mediaType); + if (SUCCEEDED(hr)) { m_bitPerPixel = bitCount; m_format = format; m_format.mediaType = mediaType->subtype; } + _DeleteMediaType(mediaType); } - - delete allocBytes; + else if (SUCCEEDED(hr)) + hr = E_FAIL; streamConfig->Release(); } - return !FAILED(ret); + return hr; } DSGrabberCallback* DSCaptureDevice::getCallback() @@ -215,7 +240,7 @@ void DSCaptureDevice::setCallback(DSGrabberCallback* callback) m_sampleGrabber->SetCallback(callback, 0); } -bool DSCaptureDevice::initDevice(IMoniker* moniker) +HRESULT DSCaptureDevice::initDevice(IMoniker* moniker) { HRESULT ret = 0; @@ -338,7 +363,7 @@ bool DSCaptureDevice::initDevice(IMoniker* moniker) videoControl->Release(); } - return setFormat(m_formats.front()); + return S_OK; } void DSCaptureDevice::initSupportedFormats() @@ -416,14 +441,14 @@ bool DSCaptureDevice::buildGraph() return false; } -bool DSCaptureDevice::start() +HRESULT DSCaptureDevice::start() { - return m_graphController ? SUCCEEDED(m_graphController->Run()) : false; + return m_graphController ? m_graphController->Run() : E_FAIL; } -bool DSCaptureDevice::stop() +HRESULT DSCaptureDevice::stop() { - return m_graphController ? SUCCEEDED(m_graphController->Stop()) : false; + return m_graphController ? m_graphController->Stop() : E_FAIL; } DSFormat DSCaptureDevice::getFormat() const diff --git a/src/native/windows/directshow/DSCaptureDevice.h b/src/native/windows/directshow/DSCaptureDevice.h index 6af3ecbe6af0feeaadcd5640933093cbc8d92e99..4c1f98302f361d60b1d724c7c00f388b45eb16bb 100644 --- a/src/native/windows/directshow/DSCaptureDevice.h +++ b/src/native/windows/directshow/DSCaptureDevice.h @@ -109,18 +109,18 @@ public: /** * \brief Initialize the device. * \param moniker moniker of the capture device - * \return true if initialization succeed, false otherwise (in this - * case the capture device have to be deleted) + * \return S_OK or S_FALSE on success or an HRESULT value describing a + * failure */ - bool initDevice(IMoniker* moniker); + HRESULT initDevice(IMoniker* moniker); /** * \brief Set video format. * \param format video format - * \return true if change is successful, false otherwise (format unsupported, ...) - * \note This method stop stream so you have to call start() after. + * \return S_OK or S_FALSE on success or an HRESULT value describing a + * failure */ - bool setFormat(const DSFormat& format); + HRESULT setFormat(const DSFormat& format); /** * \brief Get list of supported formats. @@ -149,15 +149,17 @@ public: /** * \brief Start capture device. - * \return false if problem, true otherwise + * \return S_OK or S_FALSE on success or an HRESULT value describing a + * failure */ - bool start(); + HRESULT start(); /** * \brief Stop capture device. - * \return false if problem, true otherwise + * \return S_OK or S_FALSE on success or an HRESULT value describing a + * failure */ - bool stop(); + HRESULT stop(); /** * \brief Get current format. diff --git a/src/native/windows/directshow/DSManager.cpp b/src/native/windows/directshow/DSManager.cpp index ad90c639743661d147ae50385b886068fb442953..8624777dba5ddc30da1b031569bbde14bf3e75e8 100644 --- a/src/native/windows/directshow/DSManager.cpp +++ b/src/native/windows/directshow/DSManager.cpp @@ -18,6 +18,7 @@ #include "DSManager.h" #include "DSCaptureDevice.h" #include <qedit.h> +#include <stdio.h> DSManager::DSManager() { @@ -74,15 +75,21 @@ void DSManager::initCaptureDevices() } /* get the available devices list */ - ret = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, - IID_ICreateDevEnum, (void**)&devEnum); - + ret + = CoCreateInstance( + CLSID_SystemDeviceEnum, + NULL, + CLSCTX_INPROC_SERVER, + IID_ICreateDevEnum, + (void**) &devEnum); if(FAILED(ret)) return; - ret = devEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, - &monikerEnum, 0); - + ret + = devEnum->CreateClassEnumerator( + CLSID_VideoInputDeviceCategory, + &monikerEnum, + 0); /* error or no devices */ if(FAILED(ret) || ret == S_FALSE) { @@ -119,7 +126,6 @@ void DSManager::initCaptureDevices() if(!FAILED(ret)) { VariantInit(&name); - ret = propertyBag->Read(L"FriendlyName", &name, 0); if(FAILED(ret)) { @@ -129,20 +135,15 @@ void DSManager::initCaptureDevices() continue; } - /* create a new capture device */ + /* + * Initialize a new DSCaptureDevice instance and add it to the list + * of DSCaptureDevice instances. + */ captureDevice = new DSCaptureDevice(name.bstrVal); - /* wprintf(L"%ws\n", name.bstrVal); */ - - if(captureDevice && captureDevice->initDevice(moniker)) - { - /* initialization success, add to the list */ + if(captureDevice && SUCCEEDED(captureDevice->initDevice(moniker))) m_devices.push_back(captureDevice); - } else - { - /* printf("failed to initialize device\n"); */ delete captureDevice; - } /* clean up */ VariantClear(&name); diff --git a/src/native/windows/directshow/org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice.cpp b/src/native/windows/directshow/org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice.cpp index 6f7926bf2203e4a90558d96d020dfa41123c4d2b..bd81623260bf5281fec2be69755874b533d0390e 100644 --- a/src/native/windows/directshow/org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice.cpp +++ b/src/native/windows/directshow/org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice.cpp @@ -351,46 +351,69 @@ JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_protocol_direct * \param ptr native pointer of DSCaptureDevice * \param format DSFormat to set */ -JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice_setFormat - (JNIEnv* env, jobject obj, jlong ptr, jobject format) +JNIEXPORT jint JNICALL +Java_org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice_setFormat + (JNIEnv* env, jobject obj, jlong ptr, jobject format) { - DSCaptureDevice* dev = reinterpret_cast<DSCaptureDevice*>(ptr); - DSFormat fmt; + DSCaptureDevice* thiz = reinterpret_cast<DSCaptureDevice*>(ptr); jclass clazz = env->GetObjectClass(format); + HRESULT hr; - if(clazz) + if (clazz) { - jfieldID fieldH = env->GetFieldID(clazz, "height", "I"); - jfieldID fieldW = env->GetFieldID(clazz, "width", "I"); - jfieldID fieldF = env->GetFieldID(clazz, "pixelFormat", "J"); - jlong f = env->GetLongField(format, fieldF); - jint w = env->GetIntField(format, fieldW); - jint h = env->GetIntField(format, fieldH); - - fmt.width = w; - fmt.height = h; - fmt.pixelFormat = (unsigned long)f; - - dev->setFormat(fmt); + jfieldID heightFieldID = env->GetFieldID(clazz, "height", "I"); + + if (heightFieldID) + { + jfieldID widthFieldID = env->GetFieldID(clazz, "width", "I"); + + if (widthFieldID) + { + jfieldID pixelFormatFieldID + = env->GetFieldID(clazz, "pixelFormat", "J"); + + if (pixelFormatFieldID) + { + DSFormat format_; + + format_.height = env->GetIntField(format, heightFieldID); + format_.pixelFormat + = (unsigned long) + (env->GetLongField(format, pixelFormatFieldID)); + format_.width = env->GetIntField(format, widthFieldID); + + hr = thiz->setFormat(format_); + } + else + hr = E_FAIL; + } + else + hr = E_FAIL; + } + else + hr = E_FAIL; } + else + hr = E_FAIL; + return hr; } -JNIEXPORT void JNICALL +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice_start (JNIEnv *env, jobject obj, jlong ptr) { DSCaptureDevice *thiz = reinterpret_cast<DSCaptureDevice *>(ptr); - thiz->start(); + return (jint) (thiz->start()); } -JNIEXPORT void JNICALL +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice_stop (JNIEnv *env, jobject obj, jlong ptr) { DSCaptureDevice *thiz = reinterpret_cast<DSCaptureDevice *>(ptr); - thiz->stop(); + return (jint) (thiz->stop()); } #ifdef __cplusplus diff --git a/src/native/windows/directshow/org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice.h b/src/native/windows/directshow/org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice.h index d0a9024847283822562c106f5f5add1a2dba8eed..fba28a2696e02c4f3847859310e586934da7703e 100644 --- a/src/native/windows/directshow/org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice.h +++ b/src/native/windows/directshow/org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice.h @@ -66,25 +66,25 @@ JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_protocol_direct /* * Class: org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice * Method: setFormat - * Signature: (JLorg/jitsi/impl/neomedia/jmfext/media/protocol/directshow/DSFormat;)V + * Signature: (JLorg/jitsi/impl/neomedia/jmfext/media/protocol/directshow/DSFormat;)I */ -JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice_setFormat +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice_setFormat (JNIEnv *, jobject, jlong, jobject); /* * Class: org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice * Method: start - * Signature: (J)V + * Signature: (J)I */ -JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice_start +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice_start (JNIEnv *, jobject, jlong); /* * Class: org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice * Method: stop - * Signature: (J)V + * Signature: (J)I */ -JNIEXPORT void JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice_stop +JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_jmfext_media_protocol_directshow_DSCaptureDevice_stop (JNIEnv *, jobject, jlong); #ifdef __cplusplus diff --git a/src/org/jitsi/impl/neomedia/codec/video/AVFrameFormat.java b/src/org/jitsi/impl/neomedia/codec/video/AVFrameFormat.java index 3df0d66271aabc349108bd700a3b7ae753b53905..76ecce05214eb8dfda4c03ffd9c7d8aa7f58d7af 100644 --- a/src/org/jitsi/impl/neomedia/codec/video/AVFrameFormat.java +++ b/src/org/jitsi/impl/neomedia/codec/video/AVFrameFormat.java @@ -263,6 +263,12 @@ public boolean matches(Format format) @Override public String toString() { - return super.toString() + ", pixFmt= " + pixFmt; + StringBuilder s = new StringBuilder(super.toString()); + + if (pixFmt != NOT_SPECIFIED) + s.append(", pixFmt= ").append(pixFmt); + if (deviceSystemPixFmt != NOT_SPECIFIED) + s.append(", deviceSystemPixFmt= ").append(deviceSystemPixFmt); + return s.toString(); } } diff --git a/src/org/jitsi/impl/neomedia/device/DeviceSystem.java b/src/org/jitsi/impl/neomedia/device/DeviceSystem.java index f59fc39a89ca43c7c1a02ff6eb272b9dd68e05ec..c55361e938d45cbb0bbf6ffee6606f756dc5c65b 100644 --- a/src/org/jitsi/impl/neomedia/device/DeviceSystem.java +++ b/src/org/jitsi/impl/neomedia/device/DeviceSystem.java @@ -281,9 +281,9 @@ private static void initializeDeviceSystems(String[] classNames) { if (t instanceof ThreadDeath) throw (ThreadDeath) t; - else if (logger.isDebugEnabled()) + else { - logger.debug( + logger.warn( "Failed to initialize " + className, t); } @@ -311,9 +311,9 @@ else if (logger.isDebugEnabled()) { if (t instanceof ThreadDeath) throw (ThreadDeath) t; - else if (logger.isDebugEnabled()) + else { - logger.debug( + logger.warn( "Failed to reinitialize " + className, t); } diff --git a/src/org/jitsi/impl/neomedia/device/DirectShowSystem.java b/src/org/jitsi/impl/neomedia/device/DirectShowSystem.java index 9d2205e62499894dc74c91a1db25ffc04347ec45..a58e8922c376a7a99ec8d25a54713c55e47ca311 100644 --- a/src/org/jitsi/impl/neomedia/device/DirectShowSystem.java +++ b/src/org/jitsi/impl/neomedia/device/DirectShowSystem.java @@ -6,6 +6,8 @@ */ package org.jitsi.impl.neomedia.device; +import java.util.*; + import javax.media.*; import org.jitsi.impl.neomedia.*; @@ -66,47 +68,60 @@ protected void doInitialize() i++) { DSCaptureDevice device = devices[i]; - long pixelFormat = device.getFormat().getPixelFormat(); - int ffmpegPixFmt - = (int) DataSource.getFFmpegPixFmt(pixelFormat); - Format format = null; + DSFormat[] dsFormats = device.getSupportedFormats(); String name = device.getName(); - if(ffmpegPixFmt != FFmpeg.PIX_FMT_NONE) + if (dsFormats.length == 0) + { + logger.warn( + "Camera '" + name + + "' reported no supported formats."); + continue; + } + + List<Format> formats + = new ArrayList<Format>(dsFormats.length); + + for (DSFormat dsFormat : dsFormats) { - format = new AVFrameFormat(ffmpegPixFmt, (int) pixelFormat); + long pixelFormat = dsFormat.getPixelFormat(); + int ffmpegPixFmt + = (int) DataSource.getFFmpegPixFmt(pixelFormat); + + if (ffmpegPixFmt != FFmpeg.PIX_FMT_NONE) + { + Format format + = new AVFrameFormat( + ffmpegPixFmt, + (int) pixelFormat); + + if (!formats.contains(format)) + formats.add(format); + } } - else + if (formats.isEmpty()) { logger.warn( - "No support for this webcam: " + name + "(format " - + pixelFormat + " not supported)"); + "No support for the formats of camera '" + name + + "': " + Arrays.toString(dsFormats)); continue; } + Format[] formatsArray + = formats.toArray(new Format[formats.size()]); + if(logger.isInfoEnabled()) { - for(DSFormat f : device.getSupportedFormats()) - { - if(f.getWidth() != 0 && f.getHeight() != 0) - { - logger.info( - "Webcam available resolution for " + name - + ":" + f.getWidth() + "x" - + f.getHeight()); - } - } + logger.info( + "Support for the formats of camera '" + name + + "': " + Arrays.toString(formatsArray)); } CaptureDeviceInfo cdi = new CaptureDeviceInfo( name, - new MediaLocator( - LOCATOR_PROTOCOL + ':' + name), - new Format[] { format }); - - if(logger.isInfoEnabled()) - logger.info("Found[" + i + "]: " + cdi.getName()); + new MediaLocator(LOCATOR_PROTOCOL + ':' + name), + formatsArray); CaptureDeviceManager.addDevice(cdi); captureDeviceInfoIsAdded = true; diff --git a/src/org/jitsi/impl/neomedia/jmfext/media/protocol/directshow/DSCaptureDevice.java b/src/org/jitsi/impl/neomedia/jmfext/media/protocol/directshow/DSCaptureDevice.java index 4ded28374b250e9838a2159e23b98f446a81abbc..631155e2f9c60ff2a4f60a9746ff3ad810021876 100644 --- a/src/org/jitsi/impl/neomedia/jmfext/media/protocol/directshow/DSCaptureDevice.java +++ b/src/org/jitsi/impl/neomedia/jmfext/media/protocol/directshow/DSCaptureDevice.java @@ -34,6 +34,10 @@ public static abstract class GrabberDelegate */ private static final DSFormat EMPTY_FORMATS[] = new DSFormat[0]; + public static final int S_FALSE = 1; + + public static final int S_OK = 0; + /** * Get bytes from <tt>buf</tt> native pointer and copy them * to <tt>ptr</tt> byte native pointer. @@ -141,7 +145,7 @@ public String getName() */ public DSFormat[] getSupportedFormats() { - DSFormat formats[] = getSupportedFormats(ptr); + DSFormat[] formats = getSupportedFormats(ptr); return (formats == null) ? EMPTY_FORMATS : formats; } @@ -174,10 +178,13 @@ public void setDelegate(GrabberDelegate delegate) * Set format to use with this capture device. * * @param format format to set + * @return an <tt>HRESULT</tt> value indicating whether the specified + * <tt>format</tt> was successfully set or describing a failure + * */ - public void setFormat(DSFormat format) + public int setFormat(DSFormat format) { - setFormat(ptr, format); + return setFormat(ptr, format); } /** @@ -185,20 +192,22 @@ public void setFormat(DSFormat format) * * @param ptr native pointer of <tt>DSCaptureDevice</tt> * @param format format to set + * @return an <tt>HRESULT</tt> value indicating whether the specified + * <tt>format</tt> was successfully set or describing a failure */ - private native void setFormat(long ptr, DSFormat format); + private native int setFormat(long ptr, DSFormat format); - public void start() + public int start() { - start(ptr); + return start(ptr); } - private native void start(long ptr); + private native int start(long ptr); - public void stop() + public int stop() { - stop(ptr); + return stop(ptr); } - private native void stop(long ptr); + private native int stop(long ptr); } diff --git a/src/org/jitsi/impl/neomedia/jmfext/media/protocol/directshow/DataSource.java b/src/org/jitsi/impl/neomedia/jmfext/media/protocol/directshow/DataSource.java index 800c71aa9d899a161abf156ccfcf36f4624a5558..c26d6111ee2e3b3aebed63aed5b157fb241e3fb6 100644 --- a/src/org/jitsi/impl/neomedia/jmfext/media/protocol/directshow/DataSource.java +++ b/src/org/jitsi/impl/neomedia/jmfext/media/protocol/directshow/DataSource.java @@ -417,31 +417,10 @@ protected Format setFormat( int streamIndex, Format oldValue, Format newValue) { - if (newValue instanceof AVFrameFormat) - { - AVFrameFormat avFrameFormat = (AVFrameFormat) newValue; - long pixFmt = avFrameFormat.getDeviceSystemPixFmt(); - - if (pixFmt != -1) - { - Dimension size = avFrameFormat.getSize(); - - /* - * We will set the native format in doStart() because a - * connect-disconnect-connect sequence of the native capture - * device may reorder its formats in a different way. - * Consequently, in the absence of further calls to - * setFormat() by JMF, a crash may occur later (typically, - * during scaling) because of a wrong format. - */ - if (size != null) - { - // This DataSource supports setFormat. - return newValue; - } - } - } - - return super.setFormat(streamIndex, oldValue, newValue); + // This DataSource supports setFormat. + return + DirectShowStream.isSupportedFormat(newValue) + ? newValue + : super.setFormat(streamIndex, oldValue, newValue); } } diff --git a/src/org/jitsi/impl/neomedia/jmfext/media/protocol/directshow/DirectShowStream.java b/src/org/jitsi/impl/neomedia/jmfext/media/protocol/directshow/DirectShowStream.java index f338b19e69f664eb7ad1a3875c3c3f420c899a69..03f34c6e52d6bb7e1ba8e86d74f7ff93786de627 100644 --- a/src/org/jitsi/impl/neomedia/jmfext/media/protocol/directshow/DirectShowStream.java +++ b/src/org/jitsi/impl/neomedia/jmfext/media/protocol/directshow/DirectShowStream.java @@ -15,6 +15,7 @@ import org.jitsi.impl.neomedia.codec.video.*; import org.jitsi.impl.neomedia.jmfext.media.protocol.*; +import org.jitsi.util.*; /** * Implements a <tt>PushBufferStream</tt> using DirectShow. @@ -25,6 +26,13 @@ public class DirectShowStream extends AbstractPushBufferStream { + /** + * The <tt>Logger</tt> used by the <tt>DirectShowStream</tt> class and its + * instances to print out debugging information. + */ + private static final Logger logger + = Logger.getLogger(DirectShowStream.class); + /** * The indicator which determines whether {@link #grabber} * automatically drops late frames. If <tt>false</tt>, we have to drop them @@ -132,30 +140,7 @@ private void connect() if (device == null) throw new IOException("device == null"); else - { - Format format = getFormat(); - - if (format instanceof AVFrameFormat) - { - AVFrameFormat avFrameFormat = (AVFrameFormat) format; - Dimension size = avFrameFormat.getSize(); - - if (size == null) - throw new IOException("format.size == null"); - else - { - device.setFormat( - new DSFormat( - size.width, size.height, - avFrameFormat.getDeviceSystemPixFmt())); - this.format = format; - } - } - else - throw new IOException("!(format instanceof AVFrameFormat)"); - device.setDelegate(grabber); - } } /** @@ -198,6 +183,88 @@ protected Format doGetFormat() return (format == null) ? super.doGetFormat() : format; } + /** + * {@inheritDoc} + * + * Overrides the super implementation to enable setting the <tt>Format</tt> + * of this <tt>DirectShowStream</tt> after the <tt>DataSource</tt> which + * provides it has been connected. + */ + @Override + protected Format doSetFormat(Format format) + { + if (isSupportedFormat(format)) + { + if (device == null) + return format; + else + { + try + { + setDeviceFormat(format); + } + catch (IOException ioe) + { + logger.error( + "Failed to set format on DirectShowStream: " + + format, + ioe); + /* + * Ignore the exception because the method is to report + * failures by returning null (which will be achieved + * outside the catch block). + */ + } + return format.matches(this.format) ? format : null; + } + } + else + return super.doSetFormat(format); + } + + /** + * Determines whether a specific <tt>Format</tt> appears to be suitable for + * attempts to be set on <tt>DirectShowStream</tt> instances. + * <p> + * <b>Note</b>: If the method returns <tt>true</tt>, an actual attempt to + * set the specified <tt>format</tt> on an specific + * <tt>DirectShowStream</tt> instance may still fail but that will be + * because the finer-grained properties of the <tt>format</tt> are not + * supported by that <tt>DirectShowStream</tt> instance. + * </p> + * + * @param format the <tt>Format</tt> to be checked whether it appears to be + * suitable for attempts to be set on <tt>DirectShowStream</tt> instances + * @return <tt>true</tt> if the specified <tt>format</tt> appears to be + * suitable for attempts to be set on <tt>DirectShowStream</tt> instance; + * otherwise, <tt>false</tt> + */ + static boolean isSupportedFormat(Format format) + { + if (format instanceof AVFrameFormat) + { + AVFrameFormat avFrameFormat = (AVFrameFormat) format; + long pixFmt = avFrameFormat.getDeviceSystemPixFmt(); + + if (pixFmt != -1) + { + Dimension size = avFrameFormat.getSize(); + + /* + * We will set the native format in doStart() because a + * connect-disconnect-connect sequence of the native capture + * device may reorder its formats in a different way. + * Consequently, in the absence of further calls to + * setFormat() by JMF, a crash may occur later (typically, + * during scaling) because of a wrong format. + */ + if (size != null) + return true; + } + } + return false; + } + /** * Process received frames from DirectShow capture device * @@ -484,6 +551,55 @@ void setDevice(DSCaptureDevice device) } } + /** + * Sets a specific <tt>Format</tt> on the <tt>DSCaptureDevice</tt> of this + * instance. + * + * @param format the <tt>Format</tt> to set on the <tt>DSCaptureDevice</tt> + * of this instance + * @throws IOException if setting the specified <tt>format</tt> on the + * <tt>DSCaptureDevice</tt> of this instance fails + */ + private void setDeviceFormat(Format format) + throws IOException + { + if (format == null) + throw new IOException("format == null"); + else if (format instanceof AVFrameFormat) + { + AVFrameFormat avFrameFormat = (AVFrameFormat) format; + Dimension size = avFrameFormat.getSize(); + + if (size == null) + throw new IOException("format.size == null"); + else + { + int hresult + = device.setFormat( + new DSFormat( + size.width, size.height, + avFrameFormat.getDeviceSystemPixFmt())); + + switch (hresult) + { + case DSCaptureDevice.S_FALSE: + case DSCaptureDevice.S_OK: + this.format = format; + if (logger.isDebugEnabled()) + { + logger.debug( + "Set format on DirectShowStream: " + format); + } + break; + default: + throwNewHResultException(hresult); + } + } + } + else + throw new IOException("!(format instanceof AVFrameFormat)"); + } + /** * Starts the transfer of media data from this <tt>PushBufferStream</tt>. * @@ -500,6 +616,8 @@ public void start() try { + setDeviceFormat(getFormat()); + if(!automaticallyDropsLateVideoFrames) { if (transferDataThread == null) @@ -517,8 +635,7 @@ public void run() } } - if (device != null) - device.start(); + device.start(); started = true; } @@ -541,8 +658,7 @@ public void stop() { try { - if (device != null) - device.stop(); + device.stop(); transferDataThread = null; @@ -570,4 +686,19 @@ public void stop() byteBufferPool.drain(); } } + + /** + * Throws a new <tt>IOException</tt> the detail message of which describes + * a specific <tt>HRESULT</tt> value indicating a failure. + * + * @param hresult the <tt>HRESUlT</tt> to be described by the detail message + * of the new <tt>IOException</tt> to be thrown + * @throws IOException + */ + private void throwNewHResultException(int hresult) + throws IOException + { + throw new IOException( + "HRESULT 0x" + Long.toHexString(hresult & 0xffffffffL)); + } }