Програмата увисва след извикване на Dispose()

Работя върху проект за iOS с C#. Програмата заснема изображения от свързана уеб камера и ги изпраща чрез Socket към iPhone/iPad. Всичко това работи добре и мога успешно да накарам потока си да се показва на устройството.

Но когато клиентът прекъсне връзката, уеб камерата трябва да се изключи и в тази функция програмата просто затваря. Без съобщения за грешка и извиквания за изключения...просто увисва! Вярвам, че това е проблем с множество нишки, но за съжаление не съм толкова опитен в C#, за да намеря решение. Надявам се някой тук да ме изведе на правия път...

Код:
onImageCaptured функция:

public void OnImageCaptured(Touchless.Vision.Contracts.IFrameSource frameSource, Touchless.Vision.Contracts.Frame frame, double fps)
{
    _latestFrame = frame.Image;
    Console.WriteLine("OnImageCaptured");
    if (isConnected)
    {
        Console.WriteLine("OnImageCaptured - isConnected");
        byteArray = new byte[0];
        MemoryStream stream = new MemoryStream();

        _latestFrame.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
        stream.Close();
        byteArray = stream.ToArray();

        if (byteArray.Length > 0)
        {
            string eof = "<EOF>";
            byte[] eofByte = Encoding.ASCII.GetBytes(eof);
            Console.WriteLine("OnImageCaptured - sendStream");
            this.onDataSend(byteArray);
            this.onDataSend(eofByte);
            stream.Flush();
        }

        System.Diagnostics.Debugger.Log(0, "1", "\nByte Array Length: " + byteArray.Length.ToString());
    }
    pictureBoxDisplay.Invalidate();
}

Дефиниран така в Camera Class:

public event EventHandler<CameraEventArgs> OnImageCaptured;

И задейства:

OnImageCaptured.Invoke(this, new CameraEventArgs(bitmap, fps));

Така че тази функция - това, което вярвам - работи в отделна заплаха, тъй като потребителският интерфейс не се блокира, когато изображенията идват.

След това прекъсването на връзката на клиента се обработва в тази функция:

public void onDataSend(byte[] data)
{
    clientReady = false;
    try
    {
        socketWorker.Send(data);
    }
    catch (SocketException se)
    {
        isConnected = false;
        Console.WriteLine("Error: Data Write - SocketException");
        Console.WriteLine(se.ErrorCode.ToString());
        thrashOldCamera() // THIS FUNCTION HANGS THE PROGRAM !!
        onDisconnectServer();

        // onDisconnectServer();
    }
    catch (ObjectDisposedException)
    {
        isConnected = false;
        Console.WriteLine("Error: Data Write - ObjectDisposedException");
        // onDisconnectServer();
    }

}

Клиентът прекъсва връзката, извиква се thrashOldCamera(). Досега работи добре! Сега:

private void thrashOldCamera()
{
    Console.WriteLine("TrashOldCamera");
    // Trash the old camera
    if (_frameSource != null)
    {
        try
        {
            _frameSource.NewFrame -= OnImageCaptured;
            Console.WriteLine("TrashOldCamera - 1");
            _frameSource.Camera.Dispose(); // HERE IT HANGS. IT NEVER GOES PAST HERE !!!
            Console.WriteLine("TrashOldCamera - 2");
            setFrameSource(null);
            Console.WriteLine("TrashOldCamera - 3");
            pictureBoxDisplay.Paint -= new PaintEventHandler(drawLatestImage);
        }
        catch (Exception ex)
        {
            Console.WriteLine("End Trash Camera Ex: " + ex);
        }
    }
    Console.WriteLine("End Trash Camera");
}

Програмата виси на _frameSource.Camera.Dispose();. Както беше посочено по-горе, няма грешка или изключение. Може да е проблем, че onDataReceive() се извиква в рамките на onImageCapture функция(). Добавих също бутон към формуляра, който задейства thrashOldCamera() и това работи перфектно.

Всяка помощ/съвети наистина се оценяват.


person Pascal    schedule 02.05.2012    source източник
comment
channel9 .msdn.com/Series/   -  person Lex Li    schedule 02.05.2012


Отговори (4)


Това се нарича блокиране, типичен проблем с нишката. Не виждам да извиквате изрично нишката на потребителския интерфейс навсякъде във фрагмента, така че блокирането вероятно се намира в самия фърмуер на камерата. Основният проблем е, че се опитвате да затворите камерата, докато нейното обратно извикване все още се изпълнява, няма много код, който да е устойчив на това. Извикването Release() не може да завърши, докато обратното извикване не завърши. Но обратното извикване не може да завърши, докато извикването Release() не завърши. Град безизходица.

Ще трябва да преструктурирате кода си, така че това да не може да се случи. Забавянето на освобождаването на камерата е ключово, най-добре направено в същата нишка, която е отворила камерата. Вероятно ще го разрешите, като го пуснете в събитието FormClosed например. Или изобщо да не го пускате и оставяте на Windows да затваря автоматично манипулаторите.

person Hans Passant    schedule 02.05.2012

Не знам дали това наистина трябва да е коментар или отговор, но поне мога да ви насоча по правилния път.

Намерих източника на библиотеката, която използвате. Това е съдържанието на Camera.Dispose()

public void Dispose()
{
    StopCapture();
}

Добре, няма много помощ, ето Camera.StopCapture()

internal void StopCapture()
{
    _cameraMethods.StopCamera();
}

Още веднъж, няма много помощ. _cameraMethods е тип CameraMethods, който идва от библиотеката WebCamLib, която е C++ помощна библиотека за комуникация с директно шоу.

Ето го CameraMethods::StopCamera()

void CameraMethods::StopCamera()
{
    if (g_pMediaControl != NULL)
    {
        g_pMediaControl->Stop();
        g_pMediaControl->Release();
        g_pMediaControl = NULL;
    }

    g_pfnCaptureCallback = NULL;

    if (g_pIBaseFilterNullRenderer != NULL)
    {
        g_pIBaseFilterNullRenderer->Release();
        g_pIBaseFilterNullRenderer = NULL;
    }

    if (g_pIBaseFilterSampleGrabber != NULL)
    {
        g_pIBaseFilterSampleGrabber->Release();
        g_pIBaseFilterSampleGrabber = NULL;
    }

    if (g_pIBaseFilterCam != NULL)
    {
        g_pIBaseFilterCam->Release();
        g_pIBaseFilterCam = NULL;
    }

    if (g_pGraphBuilder != NULL)
    {
        g_pGraphBuilder->Release();
        g_pGraphBuilder = NULL;
    }

    if (g_pCaptureGraphBuilder != NULL)
    {
        g_pCaptureGraphBuilder->Release();
        g_pCaptureGraphBuilder = NULL;
    }

    this->activeCameraIndex = -1;
}

Изглежда, че вашето изключение се изяжда по време на границата от родния до управлявания. Не знам доколко това ще ви помогне, но поне ви дава представа къде да търсите.

Активирайте отстраняването на грешки в неуправляван код и вижте дали можете да преминете през източника на библиотеки и да видите къде е истинският проблем.

въведете описание на изображението тук

Правя това уики на общността, ако някой друг, който има повече опит с взаимодействието на C++/C#, иска да редактира това и да добави повече от това какво следва да се направи, за да се отстрани грешката.

person Community    schedule 02.05.2012
comment
Здравей Скот. Благодаря за отговора. Със сигурност се счупва някъде там, но това е далеч над нивото ми на визуален c# - c++, за да намеря решение. Предполагам, че трябва да потърся друг скрипт за уеб камера, който не използва directShow. - person Pascal; 03.05.2012

Намерете събитието, което да извикате, докато устройството е прекъснато. Напишете кода за изключване на уеб камерата там.

person MACMAN    schedule 02.05.2012
comment
Здравей Gijo, не съм сигурен точно какво имаш предвид с това? - person Pascal; 02.05.2012
comment
Може да има събитие, което можете да използвате, за да напишете код за изключване на уеб камерата. Може би можете да проверите списъка със събития, наличен с контролата. - person MACMAN; 02.05.2012
comment
така че това, което току-що забелязах, има функция, наречена 'void Dispose()' в класа Camera. Ако използвам бутона за изключване на камерата - което работи добре - този метод не се задейства. Ако клиент прекъсне връзката, той обаче задейства тази функция за изхвърляне - person Pascal; 02.05.2012
comment
добре, можете да напишете кода на функцията void Dispose, за да изключите камерата. - person MACMAN; 02.05.2012

Само в случай, че все още има проблем с него, използвайте Touchless.RefreshCameraList, за да прекъснете връзката с камерата, можете също да добавите Touchless.CurrentCamera.Dispose, ако желаете . Все още може да се наложи да активирате отстраняване на грешки в неуправляем код

person kosi    schedule 23.02.2015