IMFSinkWriterCallback Never happens - ms-media-foundation

I'm trying to get my IMFSinkWriter's Finalize() call to be asynchronous.
So I created this
class MyMFSinkWriterCallback : public IMFSinkWriterCallback
{
public:
MyMFSinkWriterCallback();
virtual ~MyMFSinkWriterCallback();
// IMFSinkWriterCallback methods
STDMETHODIMP OnFinalize(HRESULT hrStatus);
STDMETHODIMP OnMarker(DWORD dwStreamIndex, LPVOID pvContext);
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
private:
long m_nRefCount;
};
HRESULT MyMFSinkWriterCallback::OnFinalize(HRESULT hrStatus)
{
OutputDebugStringA("MyMFSinkWriterCallback::OnFinalize\n");
return S_OK;
}
And I installed it like this
hr = pAttributes->SetUnknown(MF_SINK_WRITER_ASYNC_CALLBACK, new MyMFSinkWriterCallback());
if (SUCCEEDED(hr))
{
hr = MFCreateSinkWriterFromURL(L"C:\test.mp4", NULL, pAttributes, &MySinkWriter);
}
QueryInterface, AddRef, and Release are all being called but when I end my capture like this
OutputDebugStringA("MySinkWriter->Finalize START\n");
HRESULT hr = MySinkWriter->Finalize();
OutputDebugStringA("MySinkWriter->Finalize END\n");
All I see in my output log is
MySinkWriter->Finalize START
MySinkWriter->Finalize END
I never see
MyMFSinkWriterCallback::OnFinalize

Perhaps you don't let time to "OnFinalize" to execute. Here is a working sample code (based on Sink Writer Tutorial) :
#include <Windows.h>
#include <mfapi.h>
#include <mfidl.h>
#include <Mfreadwrite.h>
#include <mferror.h>
#include <Shlwapi.h>
#include <new>
#pragma comment(lib, "mfreadwrite")
#pragma comment(lib, "mfplat")
#pragma comment(lib, "mfuuid")
#pragma comment(lib, "Shlwapi")
template <class T> void SafeRelease(T **ppT){
if(*ppT){
(*ppT)->Release();
*ppT = NULL;
}
}
// Format constants
const UINT32 VIDEO_WIDTH = 640;
const UINT32 VIDEO_HEIGHT = 480;
const UINT32 VIDEO_FPS = 30;
const UINT64 VIDEO_FRAME_DURATION = 10 * 1000 * 1000 / VIDEO_FPS;
const UINT32 VIDEO_BIT_RATE = 800000;
const GUID VIDEO_ENCODING_FORMAT = MFVideoFormat_WMV3;
const GUID VIDEO_INPUT_FORMAT = MFVideoFormat_RGB32;
const UINT32 VIDEO_PELS = VIDEO_WIDTH * VIDEO_HEIGHT;
const UINT32 VIDEO_FRAME_COUNT = 20 * VIDEO_FPS;
// Buffer to hold the video frame data.
DWORD videoFrameBuffer[VIDEO_PELS];
class CMFSinkWriterCallback : public IMFSinkWriterCallback{
public:
CMFSinkWriterCallback(HANDLE hFinalizeEvent) : m_nRefCount(1), m_hFinalizeEvent(hFinalizeEvent){}
virtual ~CMFSinkWriterCallback(){}
// IMFSinkWriterCallback methods
STDMETHODIMP OnFinalize(HRESULT hrStatus){
OutputDebugString(L"CMFSinkWriterCallback::OnFinalize\n");
if(m_hFinalizeEvent != NULL){
SetEvent(m_hFinalizeEvent);
}
return hrStatus;
}
STDMETHODIMP OnMarker(DWORD dwStreamIndex, LPVOID pvContext){
return S_OK;
}
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID riid, void** ppv){
static const QITAB qit[] = {
QITABENT(CMFSinkWriterCallback, IMFSinkWriterCallback),
{0}
};
return QISearch(this, qit, riid, ppv);
}
STDMETHODIMP_(ULONG) AddRef(){
return InterlockedIncrement(&m_nRefCount);
}
STDMETHODIMP_(ULONG) Release(){
ULONG refCount = InterlockedDecrement(&m_nRefCount);
if(refCount == 0){
delete this;
}
return refCount;
}
private:
volatile long m_nRefCount;
HANDLE m_hFinalizeEvent;
};
HRESULT InitializeSinkWriter(IMFSinkWriter **ppWriter, DWORD *pStreamIndex, IMFSinkWriterCallback* pCallBack){
*ppWriter = NULL;
*pStreamIndex = NULL;
IMFAttributes *pAttributes = NULL;
IMFSinkWriter *pSinkWriter = NULL;
IMFMediaType *pMediaTypeOut = NULL;
IMFMediaType *pMediaTypeIn = NULL;
DWORD streamIndex = 0;
// Create the empty attribute store.
HRESULT hr = MFCreateAttributes(&pAttributes, 1);
if(SUCCEEDED(hr)){
hr = pAttributes->SetUnknown(MF_SINK_WRITER_ASYNC_CALLBACK, pCallBack);
}
if(SUCCEEDED(hr)){
hr = MFCreateSinkWriterFromURL(L"output.wmv", NULL, pAttributes, &pSinkWriter);
}
// Set the output media type.
if(SUCCEEDED(hr)){
hr = MFCreateMediaType(&pMediaTypeOut);
}
if(SUCCEEDED(hr)){
hr = pMediaTypeOut->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
}
if(SUCCEEDED(hr)){
hr = pMediaTypeOut->SetGUID(MF_MT_SUBTYPE, VIDEO_ENCODING_FORMAT);
}
if(SUCCEEDED(hr)){
hr = pMediaTypeOut->SetUINT32(MF_MT_AVG_BITRATE, VIDEO_BIT_RATE);
}
if(SUCCEEDED(hr)){
hr = pMediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
}
if(SUCCEEDED(hr)){
hr = MFSetAttributeSize(pMediaTypeOut, MF_MT_FRAME_SIZE, VIDEO_WIDTH, VIDEO_HEIGHT);
}
if(SUCCEEDED(hr)){
hr = MFSetAttributeRatio(pMediaTypeOut, MF_MT_FRAME_RATE, VIDEO_FPS, 1);
}
if(SUCCEEDED(hr)){
hr = MFSetAttributeRatio(pMediaTypeOut, MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
}
if(SUCCEEDED(hr)){
hr = pSinkWriter->AddStream(pMediaTypeOut, &streamIndex);
}
// Set the input media type.
if(SUCCEEDED(hr)){
hr = MFCreateMediaType(&pMediaTypeIn);
}
if(SUCCEEDED(hr)){
hr = pMediaTypeIn->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
}
if(SUCCEEDED(hr)){
hr = pMediaTypeIn->SetGUID(MF_MT_SUBTYPE, VIDEO_INPUT_FORMAT);
}
if(SUCCEEDED(hr)){
hr = pMediaTypeIn->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
}
if(SUCCEEDED(hr)){
hr = MFSetAttributeSize(pMediaTypeIn, MF_MT_FRAME_SIZE, VIDEO_WIDTH, VIDEO_HEIGHT);
}
if(SUCCEEDED(hr)){
hr = MFSetAttributeRatio(pMediaTypeIn, MF_MT_FRAME_RATE, VIDEO_FPS, 1);
}
if(SUCCEEDED(hr)){
hr = MFSetAttributeRatio(pMediaTypeIn, MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
}
if(SUCCEEDED(hr)){
hr = pSinkWriter->SetInputMediaType(streamIndex, pMediaTypeIn, NULL);
}
// Tell the sink writer to start accepting data.
if(SUCCEEDED(hr)){
hr = pSinkWriter->BeginWriting();
}
// Return the pointer to the caller.
if(SUCCEEDED(hr)){
*ppWriter = pSinkWriter;
(*ppWriter)->AddRef();
*pStreamIndex = streamIndex;
}
SafeRelease(&pAttributes);
SafeRelease(&pSinkWriter);
SafeRelease(&pMediaTypeOut);
SafeRelease(&pMediaTypeIn);
return hr;
}
HRESULT WriteFrame(IMFSinkWriter *pWriter, DWORD streamIndex, const LONGLONG& rtStart){
IMFSample *pSample = NULL;
IMFMediaBuffer *pBuffer = NULL;
const LONG cbWidth = 4 * VIDEO_WIDTH;
const DWORD cbBuffer = cbWidth * VIDEO_HEIGHT;
BYTE *pData = NULL;
// Create a new memory buffer.
HRESULT hr = MFCreateMemoryBuffer(cbBuffer, &pBuffer);
// Lock the buffer and copy the video frame to the buffer.
if(SUCCEEDED(hr)){
hr = pBuffer->Lock(&pData, NULL, NULL);
}
if(SUCCEEDED(hr)){
hr = MFCopyImage(pData, cbWidth, (BYTE*)videoFrameBuffer, cbWidth, cbWidth, VIDEO_HEIGHT);
}
if(pBuffer){
pBuffer->Unlock();
}
// Set the data length of the buffer.
if(SUCCEEDED(hr)){
hr = pBuffer->SetCurrentLength(cbBuffer);
}
// Create a media sample and add the buffer to the sample.
if(SUCCEEDED(hr)){
hr = MFCreateSample(&pSample);
}
if(SUCCEEDED(hr)){
hr = pSample->AddBuffer(pBuffer);
}
// Set the time stamp and the duration.
if(SUCCEEDED(hr)){
hr = pSample->SetSampleTime(rtStart);
}
if(SUCCEEDED(hr)){
hr = pSample->SetSampleDuration(VIDEO_FRAME_DURATION);
}
// Send the sample to the Sink Writer.
if(SUCCEEDED(hr)){
hr = pWriter->WriteSample(streamIndex, pSample);
}
SafeRelease(&pSample);
SafeRelease(&pBuffer);
return hr;
}
void main(){
HANDLE hFinalizeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if(hFinalizeEvent == NULL)
return;
// Set all pixels to green
for(DWORD i = 0; i < VIDEO_PELS; ++i){
videoFrameBuffer[i] = 0x000000FF;
}
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if(SUCCEEDED(hr)){
hr = MFStartup(MF_VERSION);
if(SUCCEEDED(hr)){
IMFSinkWriterCallback* pCallBack = NULL;
IMFSinkWriter *pSinkWriter = NULL;
DWORD stream;
pCallBack = new (std::nothrow)CMFSinkWriterCallback(hFinalizeEvent);
hr = pCallBack ? S_OK : E_POINTER;
if(SUCCEEDED(hr)){
hr = InitializeSinkWriter(&pSinkWriter, &stream, pCallBack);
}
if(SUCCEEDED(hr)){
// Send frames to the sink writer.
LONGLONG rtStart = 0;
for(DWORD i = 0; i < VIDEO_FRAME_COUNT; ++i){
hr = WriteFrame(pSinkWriter, stream, rtStart);
if(FAILED(hr)){
break;
}
rtStart += VIDEO_FRAME_DURATION;
}
}
if(SUCCEEDED(hr)){
hr = pSinkWriter->Finalize();
WaitForSingleObject(hFinalizeEvent, INFINITE);
}
SafeRelease(&pCallBack);
SafeRelease(&pSinkWriter);
MFShutdown();
}
CoUninitialize();
}
CloseHandle(hFinalizeEvent);
}

Related

how to determine USN_RECORD version for usn journal?

I want to learn the principle of everything, and use usn logs to monitor the addition and deletion of system files.
I wrote a piece of code under windows11, VS2019, Platform Toolset= (v142).
But I found that record->Reason (USN_RECORD) always returns 0; also, if I delete a file, I monitor that it is a garbled file name with $. For example, if I delete the file "ABC.TXT", I monitor and detect that a file name like "$1a2f5.txt" is returned. After I googled, I found that it is because USN_RECORD has multiple versions, V2, V3, V4, but I don't know how to detect the version number.
Here is the code:
#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN // 从 Windows 头中排除极少使用的资料
#endif
#include <Windows.h>
#include <stdio.h>
#include <string>
#include <iostream>
#include "usn_test.h"
//#define BUFFER_SIZE (1024 * 1024)
constexpr auto BUFFER_SIZE = sizeof(USN) + 0x100000;
HANDLE drive;
USN maxusn;
DWORDLONG gUsnJournalID;
void delete_usn()
{
DELETE_USN_JOURNAL_DATA dujd;
dujd.UsnJournalID = gUsnJournalID;
dujd.DeleteFlags = USN_DELETE_FLAG_DELETE;
DWORD br;
if (DeviceIoControl(drive,
FSCTL_DELETE_USN_JOURNAL,
&dujd,
sizeof(dujd),
nullptr,
0,
&br,
nullptr)
)
{
CloseHandle(drive);
return;
}
CloseHandle(drive);
return;
}
template<typename _T_USN_RECORD>
void check_record(_T_USN_RECORD* record)
{
WCHAR szName[MAX_PATH];
CopyMemory(szName,
((PBYTE)record) + record->FileNameOffset,
record->FileNameLength);
szName[record->FileNameLength / sizeof(WCHAR)] = 0;
std::wcout << szName << L",Reason:" << record->Reason << std::endl;
}
template<>
void check_record(USN_RECORD_V4* record)
{
WCHAR szName[MAX_PATH];
CopyMemory(szName,
((PBYTE)record) + record->Extents->Offset,
record->Extents->Length);
// Let's zero-terminate it
szName[record->Extents->Length / sizeof(WCHAR)] = 0;
std::wcout << szName << L",Reason:" << record->Reason << std::endl;
}
bool create_usn()
{
CREATE_USN_JOURNAL_DATA cujd{};
cujd.MaximumSize = 0; // 0表示使用默认值
cujd.AllocationDelta = 0; // 0表示使用默认值
DWORD br;
if (
DeviceIoControl(drive, // handle to volume
FSCTL_CREATE_USN_JOURNAL, // dwIoControlCode
&cujd, // input buffer
sizeof(cujd), // size of input buffer
nullptr, // lpOutBuffer
0, // nOutBufferSize
&br, // number of bytes returned
nullptr) // OVERLAPPED structure
)
{
return true;
}
auto&& info = "create usn error. Error code: " + std::to_string(GetLastError());
fprintf(stderr, "fileSearcherUSN: %s\n", info.c_str());
return false;
}
template<typename _T_USN_RECORD>
void read_record(DWORDLONG& nextid, void* buffer, _T_USN_RECORD*& record, _T_USN_RECORD*& recordend, const DWORD& bytecount)
{
nextid = *((DWORDLONG*)buffer);
// printf("Next ID: %lu\n", nextid);
record = (_T_USN_RECORD*)((USN*)buffer + 1);
recordend = (_T_USN_RECORD*)(((BYTE*)buffer) + bytecount);
while (record < recordend)
{
check_record(record);
record = (_T_USN_RECORD*)(((BYTE*)record) + record->RecordLength);
}
}
template<>
void read_record(DWORDLONG& nextid, void* buffer, USN_RECORD_V4*& record, USN_RECORD_V4*& recordend, const DWORD& bytecount)
{
nextid = *((DWORDLONG*)buffer);
// printf("Next ID: %lu\n", nextid);
record = (USN_RECORD_V4*)((USN*)buffer + 1);
recordend = (USN_RECORD_V4*)(((BYTE*)buffer) + bytecount);
while (record < recordend)
{
//check_record(record);
record = (USN_RECORD_V4*)(((BYTE*)record) + record->Header.RecordLength);
}
}
int main(int argc, char** argv)
{
//typedef USN_JOURNAL_DATA_V2 USN_JOURNAL_DATA;
#define FILE_END 38
//typedef MFT_ENUM_DATA MFT_ENUM_DATA_V1;
MFT_ENUM_DATA mft_enum_data;
DWORD bytecount = 1;
void* buffer;
USN_RECORD_V3* recordV3;
USN_RECORD_V3* recordendV3;
USN_RECORD_V4* recordV4;
USN_RECORD_V4* recordendV4;
USN_JOURNAL_DATA* journal;
DWORDLONG nextid{};
buffer = new BYTE[BUFFER_SIZE];
if (buffer == NULL)
{
printf("VirtualAlloc: %u\n", GetLastError());
return 0;
}
printf("Opening volume.\n");
drive = CreateFile(L"\\\\?\\h:", GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_FLAG_NO_BUFFERING, NULL);
if (drive == INVALID_HANDLE_VALUE)
{
printf("CreateFile: %u\n", GetLastError());
return 0;
}
if (!create_usn())
{
return -1;
}
printf("Calling FSCTL_QUERY_USN_JOURNAL\n");
if (!DeviceIoControl(drive, FSCTL_QUERY_USN_JOURNAL, NULL, 0, buffer, BUFFER_SIZE, &bytecount, NULL))
{
printf("FSCTL_QUERY_USN_JOURNAL: %u\n", GetLastError());
return 0;
}
// delete_usn();
journal = (USN_JOURNAL_DATA*)buffer;
gUsnJournalID = journal->UsnJournalID;
printf("UsnJournalID: %lu\n", journal->UsnJournalID);
printf("FirstUsn: %lu\n", journal->FirstUsn);
printf("NextUsn: %lu\n", journal->NextUsn);
maxusn = journal->MaxUsn;
mft_enum_data.StartFileReferenceNumber = 0;
mft_enum_data.LowUsn = 0;
mft_enum_data.HighUsn = maxusn;
mft_enum_data.MaxMajorVersion = journal->MaxSupportedMajorVersion;
mft_enum_data.MinMajorVersion = journal->MinSupportedMajorVersion;
for (;;)
{
// printf("=================================================================\n");
// printf("Calling FSCTL_ENUM_USN_DATA\n");
if (!DeviceIoControl(drive, FSCTL_ENUM_USN_DATA, &mft_enum_data, sizeof(mft_enum_data), buffer, BUFFER_SIZE, &bytecount, NULL))
{
auto bRet = GetLastError();
if (bRet != 38)
{
delete_usn();
break;
}
if (bRet == 38)//file to end
{
// break;
Sleep(1000);//wait for new file change
auto oldNextUsn = journal->NextUsn;
if (!DeviceIoControl(drive, FSCTL_QUERY_USN_JOURNAL, NULL, 0, buffer, BUFFER_SIZE, &bytecount, NULL))
{
printf("FSCTL_QUERY_USN_JOURNAL: %u\n", GetLastError());
return 0;
}
journal = (USN_JOURNAL_DATA*)buffer;
if (journal->NextUsn > oldNextUsn)//new file have changed
{
mft_enum_data.StartFileReferenceNumber = 0;
mft_enum_data.LowUsn = oldNextUsn;
mft_enum_data.HighUsn = journal->MaxUsn;
mft_enum_data.MaxMajorVersion = journal->MaxSupportedMajorVersion;
mft_enum_data.MinMajorVersion = journal->MinSupportedMajorVersion;
}
continue;
}
}
// printf("Bytes returned: %u\n", bytecount);
if(mft_enum_data.MinMajorVersion == 4)//it's wrong if i determine version by mft_enum_data.MaxMajorVersion
read_record(nextid, buffer, recordV4, recordendV4, bytecount);
else
read_record(nextid, buffer, recordV3, recordendV3, bytecount);
mft_enum_data.StartFileReferenceNumber = nextid;
}
delete[] buffer;
delete_usn();
}
I have spent 2 weeks for this.google and write a test.day and day.

How can I restart synchronous reading from webcamera every time it fails?

I am trying to read from a web camera in synchronous mode using Microsoft Media Foundation:
#include <iostream>
#include <vector>
#include <sstream>
#include <atlbase.h>
#include <mfidl.h>
#include <Mfapi.h>
#include <Mfreadwrite.h>
#pragma comment(lib,"Mfplat.lib")
#pragma comment(lib,"Mf.lib")
#pragma comment(lib,"Mfreadwrite.lib")
#pragma comment(lib,"mfuuid.lib")
#pragma comment(lib,"shlwapi.lib")
int main()
{
HRESULT hr;
DWORD dwCoInit = COINIT_MULTITHREADED;
hr = CoInitializeEx(NULL, dwCoInit);
if (FAILED(hr))
return -1;
hr = MFStartup(MF_VERSION);
if (FAILED(hr))
return -2;
CComBSTR name("M034-WDR");
CComPtr<IMFMediaSource> pMediaSource;
CComPtr<IMFSourceReader> pSourceReader;
CComPtr<IMFMediaType> pMediaType;
// Find all camera sources:
CComPtr<IMFAttributes> pAttributes;
MFCreateAttributes(&pAttributes, 1);
pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID); // camera source
CComHeapPtr<IMFActivate*> ppActivates;
UINT32 nActivateCount = 0;
MFEnumDeviceSources(pAttributes, &ppActivates, &nActivateCount);
// Loop over the camera sources, find the one with correct name:
CComPtr<IMFActivate> pActivate;
for (UINT32 nIndex = 0; nIndex < nActivateCount; nIndex++) {
CComHeapPtr<WCHAR> name_i;
UINT32 length;
ppActivates[nIndex]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &name_i, &length);
if (wcscmp(name_i, name) == 0) {
pActivate = ppActivates[nIndex];
}
reinterpret_cast<CComPtr<IMFActivate>&>(ppActivates[nIndex]).Release();
}
if (!pActivate) { // camera with name not found
return -3;
}
IMFMediaSource* source;
hr = pActivate->ActivateObject(__uuidof(IMFMediaSource), (VOID**)&source);
if (FAILED(hr))
return -4;
pMediaSource = source;
hr = MFCreateSourceReaderFromMediaSource(pMediaSource, NULL, &pSourceReader);
if (FAILED(hr))
return -5;
IMFMediaType* mediaType;
hr = pSourceReader->GetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, &mediaType);
if (FAILED(hr))
return -6;
unsigned int width, height;
hr = MFGetAttributeSize(mediaType, MF_MT_FRAME_SIZE, &width, &height);
if (FAILED(hr))
return -7;
while (true) {
CComPtr<IMFSample> pSample;
DWORD dwControlFlags = 0;
DWORD* pdwActualStreamIndex = NULL;
DWORD pdwStreamFlags;
LONGLONG timestamp;
OutputDebugStringA("MF:Before ReadSample()");
hr = pSourceReader->ReadSample(0,//dwStreamIndex,
dwControlFlags,
pdwActualStreamIndex,
&pdwStreamFlags,
&timestamp,
&pSample);
OutputDebugStringA("MF:After ReadSample()");
if (FAILED(hr)) {
std::stringstream ss;
ss << "MF:ReadSample() failed. hr = " << std::hex << hr << ".";
OutputDebugStringA(ss.str().c_str());
}
if (pSample == NULL) {
OutputDebugStringA("MF:ReadSample(): got null sample.");
}
}
}
The code above works fine on my laptop with one such webcam.
On another PC with another such webcam however; it runs fine for ca 1 minute before it starts to fail:
00000920 54.00323105 [7008] MF:Before ReadSample()
00000921 54.00324631 [7008] MF:After ReadSample()
00000922 54.00325012 [7008] MF:ReadSample() failed. hr = c00d3ea2.
00000923 54.00326538 [7008] MF:ReadSample(): got null sample.
Looking up the error code:
C:\temp>Err_6.4.5.exe c00d3ea2
# for hex 0xc00d3ea2 / decimal -1072873822
MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED mferror.h
# The video recording device is no longer present.%0
Anyways the Microsoft Camera application also experiences problems. Every minute ca. the image goes black for 1 sec ca. before the camera appears to be restarted.
How can I restart my code like Microsoft Camera does?

StoreProhibitedCause Exception with linked list on ESP8266

I have implemented a linked list class as follows for storage of sensor data readings.
(Note the total code is ~4000 lines so I can't provide it all, hopefully this gives an idea of what's done).
struct DataItem {
String _dataType;
float _dataArray[dataArraySize_const];
float _calibratedData = -1.0;
float _rawData = -1.0;
DataItem *_next;
uint8_t _dataArraySize = dataArraySize_const;
float *_calibrationParameters;
uint8_t _numCalibrationParameters;
};
class DataContainer {
public:
DataContainer() {
_head = NULL;
_tail = NULL;
};
DataItem* addDataItem(String dataTypeIn, float calibrationParameters[10], uint8_t numberOfCalibrationParameters) {
DataItem *temp = new DataItem;
temp->_dataType = dataTypeIn;
temp->_calibratedData = -1.0;
temp->_rawData = -1.0;
for (uint8_t i = 0; i < dataArraySize_const; i++) { temp->_dataArray[i] = 0; } //Setting all the data array to 0
temp->_calibrationParameters = calibrationParameters;
temp->_numCalibrationParameters = numberOfCalibrationParameters;
temp->_next = NULL;
if(_head == NULL) {
_head = temp;
_tail = temp;
temp = NULL;
}
else {
_tail->_next = temp;
_tail = temp;
}
return temp;
};
uint8_t setDataValue(String dataType, float value, uint8_t arrayIndex) {
DataItem *temp = new DataItem;
temp = _head;
Serial.println("Addresses: ");
while(temp != NULL) {
Serial.print("temp address: 0x");
Serial.println((unsigned long)temp, HEX);
Serial.print("head address: 0x");
Serial.println((unsigned long)_head, HEX);
Serial.print("temp add address: 0x");
Serial.println((unsigned long)&temp, HEX);
if (temp->_dataType == dataType) { break; }
else if (temp == NULL) { return 1; }
temp = temp->_next;
}
temp->_dataArray[arrayIndex] = value;
float sum = 0.0;
for (uint8_t i = 0; i < dataArraySize_const; i++) {
sum += temp->_dataArray[i];
}
temp->_rawData = sum/dataArraySize_const;
Serial.println("Pre calibration");
this->calibrate(temp);
Serial.println("Finished calibration");
return 0;
};
void calibrate(DataItem *temp) {
temp->_calibratedData = temp->_calibrationParameters[0];
for (uint8_t i = 1; i <= temp->_numCalibrationParameters; i++) {
temp->_calibratedData += temp->_calibrationParameters[i] * pow(temp->_rawData, i);
}
}
uint8_t setCalibrationParameters(String dataType, float calibrationParameters[10]) {
DataItem *temp = new DataItem;
temp = _head;
while(temp != NULL) {
if (temp->_dataType == dataType) { break; }
else if (temp == NULL) { return 1; }
temp = temp->_next;
}
temp->_calibrationParameters = calibrationParameters;
return 0;
};
private:
DataItem *_head, *_tail;
};
uint8_t numUsedCalibrationParameters = 10;
float calibrationParam[numUsedCalibrationParameters] = {0,1,0,0,0,0,0,0,0,0};
uint8_t dataArrayPosition = 0;
uint8_t dataArraySize = 10;
void setup(void) {
Serial.begin(115200);
Serial.setDebugOutput(false);
delay(20);
Serial.println("\n\nbegin");
pinMode(A0, INPUT);
dataContainer.addDataItem("ADC",calibrationParam,numUsedCalibrationParameters);
void loop(void) {
dataContainer.setDataValue("ADC", analogRead(A0), dataArrayPosition);
if (dataArrayPosition < dataArraySize) { ++dataArrayPosition; }
else { dataArrayPosition = 0; }
delay(100);
}
After around 31000 loops (just under 2^15 which is suspicious to me), I get a StoreProhibitedCause Exception. If I comment out dataContainer.setDataValue("ADC", analogRead(A0), dataArrayPosition);, I no longer get the exception. I suspect it's some way that I have implemented the linked list and it has a memory issue but I have tried printing out the addresses of everything and it doesn't look like anything is running away.
Exception:
Exception (29):
epc1=0x4000df64 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000
>>>stack>>>
ctx: sys
sp: 3fffec10 end: 3fffffb0 offset: 01a0
3fffedb0: 4024576b 3fff0b08 00000002 40245700
.....
===================== SOLVED =====================
DataItem *temp = new DataItem; should be DataItem *temp; for setDataValue() and setCalibrationParameters().
Otherwise it keeps on creating new structs for every addition.
DataItem *temp = new DataItem; should be DataItem *temp; for setDataValue() and setCalibrationParameters().
Otherwise it keeps on creating new structs for every addition.
(I can't mark it solved without having an answer).

In QT i have function xyz() and i need to return QImage and QString both?

In the function xyz(), I am calculating the string value and number of image and I need to return all the value like string and image. So, What I need to take the return type so they will take all value?
<Return-Type> MainWindow::xyz(QString m_ImgPath, int i)
{
try
{
m_ImgPath = Array[i];
QByteArray m_path = m_ImgPath.toLocal8Bit();
char* ImagePath = m_path.data();
obj *m_ThumpDCMReader = obj::New();
TReader->SetFileName(ImagePath);
TReader->Update();
//const QString string = NULL;
const char *str_uchar = TReader->GetMetaData()->GetAttributeValue(DC::string).GetCharData();
string = QString::fromUtf8((char *)str_uchar);
SPointer<ImageData> imageData = TReader->GetOutput();
if (!imageData) { return QImage(); }
/// \todo retrieve just the UpdateExtent
int width = imageData->GetDimensions()[0];
int height = imageData->GetDimensions()[1];
QImage image(width, height, QImage::Format_RGB32);
QRgb *rgbPtr = reinterpret_cast<QRgb *>(image.bits()) + width * (height - 1);
unsigned char *colorsPtr = reinterpret_cast<unsigned char *>(imageData->GetScalarPointer());
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width; col++)
{
*(rgbPtr++) = QColor(colorsPtr[0], colorsPtr[1], colorsPtr[2]).rgb();
colorsPtr += imageData->GetNumberOfScalarComponents();
}
rgbPtr -= width * 2;
}
return (Image,string)
}
catch (...) { return QImage(); }
}
SO what i need to add the the return type.So, they will return multiple data.
You can use a QPair<QString, QImage> for that, and use qMakePair to build the values:
QPair<QString, QImage> MainWindow::xyz(QString m_ImgPath, int i) {
try {
// ...
return qMakePair(string, Image);
} catch (...) {
return qMakePair(QString(), QImage());
}
}
The caller can then use .first and .second to access the string and image, resp:
auto values = xyz("",0); // or QPair<QString, QImage> values = xyz("",0);
auto str = values.first;
auto img = values.second;
If you need to extend to more then 2 items, I suggest to use a custom struct, e.g.:
struct StringWithImage {
QString string;
QImage image;
};
// In your return:
return StringWithImage{ string, Image };
// Usage:
auto values = xyz("", 0);
auto str = values.string;
auto img = values.image;

Nginx Module Post parse Request timeout

I wrote a custom module for parse GET, POST, Cookie, Header request. This works fine but when I request by POST then first request working fine, after that second request not responding. going request time. I can't understand what's the problem. I was flowing:
this module.
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#include "ngx_http_ab_router_service.h"
static char *ngx_http_ab_router_post_init(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_int_t ngx_http_ab_router_prefix_init(ngx_conf_t *cf);
ngx_flag_t ngx_http_ab_router_post_read_used = 0;
static ngx_int_t ngx_http_ab_router_request_handler(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "CALLED HANDLER");
static char *prefix = NULL;
char *header_params_name = "access_token";
ngx_http_ab_router_post_read_used = 1;
/*Parse Cookie Portion*/
ngx_int_t response;
ngx_str_t cookie_key = (ngx_str_t) ngx_string("ckisession");
ngx_str_t cookie_value;
response = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &cookie_key, &cookie_value);
if (response != NGX_DECLINED) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, (char *) cookie_value.data);
prefix = (char *) cookie_value.data;
} else {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Cookie to nai");
}
/*Parse Header Portion*/
if (ngx_http_ab_router_headers_value(r, header_params_name, &prefix) == NGX_OK) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, prefix);
} else if (r->method == NGX_HTTP_GET) {
/*Parse GET Request Parameter Portion*/
if (ngx_http_ab_router_get_params(r, &prefix) == NGX_OK) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, prefix);
}
} else if (r->method == NGX_HTTP_POST) {
if (ngx_http_ab_router_parse_post_json(r, &prefix) == NGX_OK) {
}
}
if (prefix != NULL) {
char *buffer;
if (ngx_http_ab_router_decrypt_prifix(prefix, &buffer) == NGX_OK) {
ngx_http_variable_value_t *vv = v;
vv->data = (u_char *) buffer;
if (vv->data == NULL) {
vv->valid = 0;
vv->not_found = 1;
} else {
vv->len = ngx_strlen(vv->data);
vv->valid = 1;
vv->no_cacheable = 0;
vv->not_found = 0;
}
}
return NGX_OK;
} else {
return NGX_OK;
;
}
}
static ngx_command_t ngx_http_ab_router_commands[] = {
{ ngx_string("ab_server_type"),
NGX_HTTP_LOC_CONF | NGX_CONF_NOARGS,
ngx_http_ab_router_post_init,
0,
0,
NULL},
ngx_null_command
};
static ngx_http_module_t ngx_http_ab_router_module_ctx = {
NULL, /* preconfiguration */
ngx_http_ab_router_prefix_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
NULL, /* create location configuration */
NULL /* merge location configuration */
};
ngx_module_t ngx_http_ab_router_module = {
NGX_MODULE_V1,
&ngx_http_ab_router_module_ctx, /* module context */
ngx_http_ab_router_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
typedef struct {
unsigned done : 1;
unsigned waiting_more_body : 1;
} ngx_http_ab_router_ctx_t;
static void
ngx_http_ab_router_post_read(ngx_http_request_t *r) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Request Body Here");
ngx_http_ab_router_ctx_t *ctx;
ctx = ngx_http_get_module_ctx(r, ngx_http_ab_router_module);
ctx->done = 1;
#if defined(nginx_version) && nginx_version >= 8011
dd("count--");
r->main->count--;
#endif
/* waiting_more_body my rewrite phase handler */
if (ctx->waiting_more_body) {
ctx->waiting_more_body = 0;
ngx_http_core_run_phases(r);
}
}
static ngx_int_t
ngx_http_ab_router_post_parser(ngx_http_request_t *r) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "CALLED POST REQUEST");
ngx_http_ab_router_ctx_t *ctx;
ngx_int_t rc;
ctx = ngx_http_get_module_ctx(r, ngx_http_ab_router_module);
if (ctx != NULL) {
if (ctx->done) {
return NGX_DECLINED;
}
return NGX_DONE;
}
if (r->method != NGX_HTTP_POST) {
return NGX_DECLINED;
}
ctx = ngx_pcalloc(r->pool, sizeof (ngx_http_ab_router_ctx_t));
if (ctx == NULL) {
return NGX_ERROR;
}
ngx_http_set_ctx(r, ctx, ngx_http_ab_router_module);
rc = ngx_http_read_client_request_body(r, ngx_http_ab_router_post_read);
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
#if (nginx_version < 1002006) || \
(nginx_version >= 1003000 && nginx_version < 1003009)
r->main->count--;
#endif
return rc;
}
if (rc == NGX_AGAIN) {
ctx->waiting_more_body = 1;
return NGX_DONE;
}
return NGX_DECLINED;
}
static ngx_int_t ngx_http_ab_router_prefix_init(ngx_conf_t *cf) {
ngx_http_variable_t *ab_prefix_var;
ngx_str_t ab_prefix_var_name = ngx_string("ab_prefix");
ab_prefix_var = ngx_http_add_variable(cf, &ab_prefix_var_name, NGX_HTTP_VAR_NOCACHEABLE);
if (ab_prefix_var == NULL) {
return NGX_ERROR;
}
ab_prefix_var->get_handler = ngx_http_ab_router_request_handler;
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
if (h == NULL) {
return NGX_ERROR;
}
*h = ngx_http_ab_router_post_parser;
return NGX_OK;
}
static char *ngx_http_ab_router_post_init(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
return NGX_CONF_OK;
}
At the end i got the solution. When any one register a new rewrite phase handler like as
ngx_http_read_client_request_body(r, ngx_http_ab_router_post_read);
in nginx after work done need to remove that rewrite phase handler from main. like as
r->main->count--;
That was the problem I not removing the handler.

Resources