RTSP streams that use Media Foundation stop loading.

MASAHIROTANAKA-1764 0 Reputation points
2023-10-31T07:00:03.3066667+00:00

I'm writing an application that uses Media Foundation to read and parse RTSP streams.

The stream will be in H.264 codec at 25 fps.

I can get images using Media Foundation's SourceReader, but it stops at ReadSample() after about 1-2 minute.

There's no reception on Ethernet in Windows Task Manager, so I think it's disconnected.

Does anyone know why ReadSample() stops on its own?

// SourceReader.h
#pragma once
using namespace System;
using namespace System::Collections::Generic;
#using <system.drawing.dll>
using namespace System::Drawing::Imaging;
using namespace System::Threading;

namespace MediaFoundationCLILib
{
	public ref class ReadSampleProcessParameter
	{
	public:
		String^ Url;
	};

 	public ref class SourceReaderSample
	{
	public:
		array<Byte>^ Image;
		Int32 Width;
		Int32 Height;
		Int32 Stride;
		PixelFormat PixelFormat;
		FLOAT Fps;
	};

 	public ref class SourceReader
	{
	public:
		SourceReader(String^ url);
		~SourceReader();
		!SourceReader();
		void Start();
		void Stop();
		Action<SourceReaderSample^>^ ReadSample;
	protected:
		String^ Url = String::Empty;
	private:
		Thread^ ReadSampleThread = nullptr;
		Boolean ReadSampleProcessFlag = false;
		SourceReader() {};
		void ReadSampleProcess(Object^ parameter);
	};
}

// SourceReader.cpp
#include "pch.h"
#include <msclr\marshal.h>
#include "SourceReader.h"
using namespace System::Runtime::InteropServices;
using namespace msclr::interop;
using namespace MediaFoundationCLILib;

template <class T> void SafeRelease(T** ppT)
{
 	if (*ppT)
 	{
 		(*ppT)->Release();
 		*ppT = nullptr;
 	}
}

SourceReader::SourceReader(String^ url)
{
 	this->Url = url;
}

SourceReader::~SourceReader()
{
 	this->!SourceReader();
}

SourceReader::!SourceReader()
{
 	this->Stop();
}

void SourceReader::Start()
{
	this->Stop();
	auto readSampleProcessParameter = gcnew ReadSampleProcessParameter();
	readSampleProcessParameter->Url = this->Url;
	this->ReadSampleThread = gcnew Thread(gcnew ParameterizedThreadStart(this, &SourceReader::ReadSampleProcess));
	this->ReadSampleThread->Start(readSampleProcessParameter);
}

void SourceReader::Stop()
{
	this->ReadSampleProcessFlag = false;
	if (this->ReadSampleThread != nullptr)
	{
		this->ReadSampleThread->Join();
		this->ReadSampleThread = nullptr;
	}
}

 void SourceReader::ReadSampleProcess(Object^ parameter)
{
	auto readSampleProcessParameter = (ReadSampleProcessParameter^)parameter;
	marshal_context context;
	auto pwszURL = context.marshal_as<const TCHAR*>(readSampleProcessParameter->Url);
	HRESULT hr;
	IMFAttributes* pAttributes = nullptr;
	IMFSourceReader* pSourceReader = nullptr;
	IMFMediaType* pNewMediaType = nullptr;
	IMFMediaType* pMediaType = nullptr;
	try
	{
		// Create output media type(RGB32bit)
		hr = MFCreateAttributes(&pAttributes, 1);
		if (FAILED(hr))
		{
			throw gcnew Exception(String::Format("SourceReader::ReadSampleProcess() step01,HRESULT:{0:X}", hr));
		}
		hr = pAttributes->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, TRUE);
		if (FAILED(hr))
		{
			throw gcnew Exception(String::Format("SourceReader::ReadSampleProcess() step02,HRESULT:{0:X}", hr));
		}

		// Create SourceReader
		hr = MFCreateSourceReaderFromURL(pwszURL, pAttributes, &pSourceReader);
		if (FAILED(hr))
		{
			throw gcnew Exception(String::Format("SourceReader::ReadSampleProcess() step03,Exception:{0:X}", hr));
		}

		// Set output media type(RGB32bit)
		hr = MFCreateMediaType(&pNewMediaType);
		if (FAILED(hr))
		{
			throw gcnew Exception(String::Format("SourceReader::ReadSampleProcess() step04,Exception:{0:X}", hr));
		}
		hr = pNewMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
		hr = pNewMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32);
		hr = pSourceReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, nullptr, pNewMediaType);
		if (FAILED(hr))
		{
			throw gcnew Exception(String::Format("SourceReader::ReadSampleProcess() step05,Exception:{0:X}", hr));
		}
		SafeRelease(&pNewMediaType);

		// Video Information
		// stride:Bytes per image line
		// width:Image width
		// height:Image height
		hr = pSourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, &pMediaType);
		if (FAILED(hr))
		{
			throw gcnew Exception(String::Format("SourceReader::ReadSampleProcess() step06,Exception:{0:X}", hr));
		}
		auto stride = (INT32)MFGetAttributeUINT32(pMediaType, MF_MT_DEFAULT_STRIDE, 0);
		UINT32 width = 0;
		UINT32 height = 0;
		hr = MFGetAttributeSize(pMediaType, MF_MT_FRAME_SIZE, &width, &height);
		if ((stride == 0) || FAILED(hr))
		{
			throw gcnew Exception(String::Format("SourceReader::ReadSampleProcess() step07,Exception:{0}", hr));
		}
		SafeRelease(&pMediaType);

		// Get frame
		DWORD dwActualStreamIndex;
		DWORD dwStreamFlags;
		LONGLONG llTimestamp;
		IMFSample* pSample = nullptr;
		IMFMediaBuffer* pMediaBuffer = nullptr;
		auto frameCount = 0;
		auto fps = 0.0f;
		auto stopwatch = gcnew System::Diagnostics::Stopwatch();
		stopwatch->Restart();
		this->ReadSampleProcessFlag = true;
		while (this->ReadSampleProcessFlag)
		{
			hr = pSourceReader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, &dwActualStreamIndex, &dwStreamFlags, &llTimestamp, &pSample);
			if (FAILED(hr))
			{
				break;
			}
			else if (dwStreamFlags & MF_SOURCE_READERF_ERROR)
			{
				break;
			}
			else if (dwStreamFlags & MF_SOURCE_READERF_ENDOFSTREAM)
			{
				break;
			}
			else if (pSample == nullptr)
			{
				continue;
			}

			// FPS
			frameCount++;
			if (frameCount >= 25)
			{
				stopwatch->Stop();
				fps = (1000.0f / stopwatch->ElapsedMilliseconds) * frameCount;
				stopwatch->Restart();
				frameCount = 0;
			}

			if (ReadSample != nullptr)
			{
				DWORD cbCurrentLength = 0;
				BYTE* pBuffer = nullptr;
				hr = pSample->ConvertToContiguousBuffer(&pMediaBuffer);
				hr = pMediaBuffer->Lock(&pBuffer, nullptr, &cbCurrentLength);
				auto image = gcnew array<Byte>(stride * height);
				Marshal::Copy((IntPtr)pBuffer, image, 0, stride * height);
				hr = pMediaBuffer->Unlock();
				SafeRelease(&pMediaBuffer);
				SourceReaderSample^ sourceReaderSample = gcnew SourceReaderSample();
				sourceReaderSample->Image = image;
				sourceReaderSample->Width = width;
				sourceReaderSample->Height = height;
				sourceReaderSample->Stride = stride;
				sourceReaderSample->PixelFormat = PixelFormat::Format32bppRgb;
				sourceReaderSample->Fps = fps;
				ReadSample(sourceReaderSample);
			}
			SafeRelease(&pSample);
			Thread::Sleep(20);
		}
	}
	catch (Exception^)
	{
	}
	finally
	{
		SafeRelease(&pMediaType);
		SafeRelease(&pNewMediaType);
		SafeRelease(&pSourceReader);
		SafeRelease(&pAttributes);
	}
}

.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,573 questions
.NET CLI
.NET CLI
A cross-platform toolchain for developing, building, running, and publishing .NET applications.
326 questions
C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,612 questions
{count} votes