IMFTransform interface of Color Converter DSP giving E_INVALIDARG on SetInputType/SetOutputType - winapi

I'm trying to use Color Converter DMO (http://msdn.microsoft.com/en-us/library/windows/desktop/ff819079(v=vs.85).aspx) to convert RBG24 to YV12/NV12 via Media Foundation. I've created an instance of Color Converter DSP via CLSID_CColorConvertDMO and then tried to set the needed input/output types, but the calls always return E_INVALIDARG even when using media types that are returned by GetOutputAvailableType and GetInputAvailableType. If I set the media type to NULL then i get the error that the media type is invalid, that makes sense. I've seen examples from MSDN, where people do the same - enumerate available types and then set them as input types - and they claim it works, but i'm kinda stuck on the E_INVALIDARG. I understand that this is hard to answer without a code example, if no one has had similar experience, I'll try to post a snipplet, but maybe someone has experienced the same issue?

This DMO/DSP is dual interfaced and is both a DMO with IMediaObject and an MFT with IMFTransform. The two interfaces share a lot common, and here is a code snippet to test initialization of RGB24 into YV12 conversion:
#include "stdafx.h"
#include <dshow.h>
#include <dmo.h>
#include <wmcodecdsp.h>
#pragma comment(lib, "strmiids.lib")
#pragma comment(lib, "wmcodecdspuuid.lib")
int _tmain(int argc, _TCHAR* argv[])
{
ATLVERIFY(SUCCEEDED(CoInitialize(NULL)));
CComPtr<IMediaObject> pMediaObject;
ATLVERIFY(SUCCEEDED(pMediaObject.CoCreateInstance(CLSID_CColorConvertDMO)));
VIDEOINFOHEADER InputVideoInfoHeader;
ZeroMemory(&InputVideoInfoHeader, sizeof InputVideoInfoHeader);
InputVideoInfoHeader.bmiHeader.biSize = sizeof InputVideoInfoHeader.bmiHeader;
InputVideoInfoHeader.bmiHeader.biWidth = 1920;
InputVideoInfoHeader.bmiHeader.biHeight = 1080;
InputVideoInfoHeader.bmiHeader.biPlanes = 1;
InputVideoInfoHeader.bmiHeader.biBitCount = 24;
InputVideoInfoHeader.bmiHeader.biCompression = BI_RGB;
InputVideoInfoHeader.bmiHeader.biSizeImage = 1080 * (1920 * 3);
DMO_MEDIA_TYPE InputMediaType;
ZeroMemory(&InputMediaType, sizeof InputMediaType);
InputMediaType.majortype = MEDIATYPE_Video;
InputMediaType.subtype = MEDIASUBTYPE_RGB24;
InputMediaType.bFixedSizeSamples = TRUE;
InputMediaType.bTemporalCompression = FALSE;
InputMediaType.lSampleSize = InputVideoInfoHeader.bmiHeader.biSizeImage;
InputMediaType.formattype = FORMAT_VideoInfo;
InputMediaType.cbFormat = sizeof InputVideoInfoHeader;
InputMediaType.pbFormat = (BYTE*) &InputVideoInfoHeader;
const HRESULT nSetInputTypeResult = pMediaObject->SetInputType(0, &InputMediaType, 0);
_tprintf(_T("nSetInputTypeResult 0x%08x\n"), nSetInputTypeResult);
VIDEOINFOHEADER OutputVideoInfoHeader = InputVideoInfoHeader;
OutputVideoInfoHeader.bmiHeader.biBitCount = 12;
OutputVideoInfoHeader.bmiHeader.biCompression = MAKEFOURCC('Y', 'V', '1', '2');
OutputVideoInfoHeader.bmiHeader.biSizeImage = 1080 * 1920 * 12 / 8;
DMO_MEDIA_TYPE OutputMediaType = InputMediaType;
OutputMediaType.subtype = MEDIASUBTYPE_YV12;
OutputMediaType.lSampleSize = OutputVideoInfoHeader.bmiHeader.biSizeImage;
OutputMediaType.cbFormat = sizeof OutputVideoInfoHeader;
OutputMediaType.pbFormat = (BYTE*) &OutputVideoInfoHeader;
const HRESULT nSetOutputTypeResult = pMediaObject->SetOutputType(0, &OutputMediaType, 0);
_tprintf(_T("nSetOutputTypeResult 0x%08x\n"), nSetOutputTypeResult);
// TODO: ProcessInput, ProcessOutput
pMediaObject.Release();
CoUninitialize();
return 0;
}
This should work fine and print two S_OKs out...

Related

FFMPEG- H.264 encoding BGR image data to YUP420P video file resulting in empty video

I'm new to FFMPEG and trying to use it to do some screen capture to a video file, but after a lot of online searching I am stumped as to what I'm doing wrong. Basically, I've already done the effort of capturing screen data via DirectX which stores in a BGR pixel format and I'm just trying to put each frame in a video file. There's two functions, setup which does all the ffmpeg initialization work, and addImage which is called in the main program loop and puts each buffer of BGR image data into a video file. The technique I'm doing for this is to make two frames, one with the BGR data and one with YUP420P (doesn't need to be the latter but after a lot of trial and error it was all I was able to get working with H.264), and use sws_scale to copy data between the two, and then send that frame to video.mp4. The file seems to be having data written to it successfully (the file size grows and grows as the program runs), but when I try and view it in VLC I see nothing- indeed, VLC fails to fetch a length of the video, and bringing up codec and media information both are empty. I turned on ffmpeg verbose logging but all that is spit out is the following:
Setting default whitelist 'Epu��'
Timestamps are unset in a packet for stream -1259342440. This is deprecated and will stop working in the future. Fix your code to set the timestamps properly
Encoder did not produce proper pts, making some up.
From what I am reading, I understand this to be warnings rather than errors that would totally corrupt my video file. I separately went through all the error codes being spit out and everything seems nominal to me (zero for success for most calls, -11 sometimes for avcodec_receive_packet but the docs indicate that's expected sometimes).
Based on my understanding of things as they are, this should be working, but isn't, and the logs and error codes give me nothing to go on, so someone with experience with this I reckon would save me a ton of time. The code is as follows:
VideoService.h
#ifndef VIDEO_SERVICE_H
#define VIDEO_SERVICE_H
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}
class VideoService {
public:
void setup();
void addImage(unsigned char* data, int lineSize, int width, int height, int align);
private:
AVCodecContext* context;
AVFormatContext* formatContext;
AVFrame* bgrFrame;
AVFrame* yuvFrame;
AVStream* videoStream;
SwsContext* swsContext;
};
#endif
VideoService.cpp
#include "VideoService.h"
#include <stdio.h>
void FfmpegLogCallback(void *ptr, int level, const char *fmt, va_list vargs)
{
FILE* f = fopen("ffmpeg.txt", "a");
fprintf(f, fmt, vargs);
fclose(f);
}
void VideoService::setup() {
int result = 0;
av_log_set_level(AV_LOG_VERBOSE);
av_log_set_callback(FfmpegLogCallback);
bgrFrame = av_frame_alloc();
bgrFrame->width = 1920;
bgrFrame->height = 1080;
bgrFrame->format = AV_PIX_FMT_BGRA;
bgrFrame->time_base.num = 1;
bgrFrame->time_base.den = 60;
result = av_frame_get_buffer(bgrFrame, 1);
yuvFrame = av_frame_alloc();
yuvFrame->width = 1920;
yuvFrame->height = 1080;
yuvFrame->format = AV_PIX_FMT_YUV420P;
yuvFrame->time_base.num = 1;
yuvFrame->time_base.den = 60;
result = av_frame_get_buffer(yuvFrame, 1);
const AVOutputFormat* outputFormat = av_guess_format("mp4", "video.mp4", "video/mp4");
result = avformat_alloc_output_context2(
&formatContext,
outputFormat,
"mp4",
"video.mp4"
);
formatContext->oformat = outputFormat;
const AVCodec* codec = avcodec_find_encoder(AVCodecID::AV_CODEC_ID_H264);
result = avio_open2(&formatContext->pb, "video.mp4", AVIO_FLAG_WRITE, NULL, NULL);
videoStream = avformat_new_stream(formatContext, codec);
AVCodecParameters* codecParameters = videoStream->codecpar;
codecParameters->codec_type = AVMediaType::AVMEDIA_TYPE_VIDEO;
codecParameters->codec_id = AVCodecID::AV_CODEC_ID_HEVC;
codecParameters->width = 1920;
codecParameters->height = 1080;
codecParameters->format = AVPixelFormat::AV_PIX_FMT_YUV420P;
videoStream->time_base.num = 1;
videoStream->time_base.den = 60;
result = avformat_write_header(formatContext, NULL);
codec = avcodec_find_encoder(videoStream->codecpar->codec_id);
context = avcodec_alloc_context3(codec);
context->time_base.num = 1;
context->time_base.den = 60;
avcodec_parameters_to_context(context, videoStream->codecpar);
result = avcodec_open2(context, codec, nullptr);
swsContext = sws_getContext(1920, 1080, AV_PIX_FMT_BGRA, 1920, 1080, AV_PIX_FMT_YUV420P, 0, 0, 0, 0);
}
void VideoService::addImage(unsigned char* data, int lineSize, int width, int height, int align) {
int result = 0;
result = av_image_fill_arrays(bgrFrame->data, bgrFrame->linesize, data, AV_PIX_FMT_BGRA, 1920, 1080, 1);
sws_scale(swsContext, bgrFrame->data, bgrFrame->linesize, 0, 1080, &yuvFrame->data[0], yuvFrame->linesize);
result = avcodec_send_frame(context, yuvFrame);
AVPacket *packet = av_packet_alloc();
result = avcodec_receive_packet(context, packet);
if (result != 0) {
return;
}
result = av_interleaved_write_frame(formatContext, packet);
}
My environment is windows 10, I'm building with clang++ 12.0.1, and using the FFMPEG 5.1 libs.
See the official sample, muxing.c.
Fix you code like the following.
Set fields of an AVCodecContext and call the avcodec_parameters_from_context(), instead of calling the avcodec_parameters_to_context(). You should set width, height, bit_rate, pix_fmt, framerate and time_base at least.(See the implementation of the add_stream() in the sample.)
Specify an algorithm such as the SWS_BILINEAR when calling the sws_getContext().(Although a default algorithm will be selected, that's an undocumented feature.)
Set the pts(presentation timestamp) field of an AVFrame.
Implement a loop calling the avcodec_receive_packet() after calling the avcodec_send_frame(). See the write_frame() in the sample.(Single frame can result in multiple packets.)

How to produce same mfcc result as librosa using aubio?

I am trying to calculate Mfcc feature in C++. And I found Aubio (https://github.com/aubio/aubio) but I cannot produce same result as Librosa of Python (this is important).
Librosa code:
X, sample_rate = sf.read(file_name, dtype='float32')
mfccs = librosa.feature.mfcc(y=X, sr=sample_rate, n_mfcc=40)
Aubio code:
#include "utils.h"
#include "parse_args.h"
#include <stdlib.h>
aubio_pvoc_t *pv; // a phase vocoder
cvec_t *fftgrain; // outputs a spectrum
aubio_mfcc_t * mfcc; // which the mfcc will process
fvec_t * mfcc_out; // to get the output coefficients
uint_t n_filters = 128;
uint_t n_coefs = 40;
void process_block (fvec_t *ibuf, fvec_t *obuf)
{
fvec_zeros(obuf);
//compute mag spectrum
aubio_pvoc_do (pv, ibuf, fftgrain);
//compute mfccs
aubio_mfcc_do(mfcc, fftgrain, mfcc_out);
}
void process_print (void)
{
/* output times in selected format */
print_time (blocks * hop_size);
outmsg ("\t");
/* output extracted mfcc */
fvec_print (mfcc_out);
}
int main(int argc, char **argv) {
int ret = 0;
// change some default params
buffer_size = 2048;
hop_size = 512;
examples_common_init(argc,argv);
verbmsg ("using source: %s at %dHz\n", source_uri, samplerate);
verbmsg ("buffer_size: %d, ", buffer_size);
verbmsg ("hop_size: %d\n", hop_size);
pv = new_aubio_pvoc (buffer_size, hop_size);
fftgrain = new_cvec (buffer_size);
mfcc = new_aubio_mfcc(buffer_size, n_filters, n_coefs, samplerate);
mfcc_out = new_fvec(n_coefs);
if (pv == NULL || fftgrain == NULL || mfcc == NULL || mfcc_out == NULL) {
ret = 1;
goto beach;
}
examples_common_process(process_block, process_print);
printf("\nlen=%u\n", mfcc_out->length);
del_aubio_pvoc (pv);
del_cvec (fftgrain);
del_aubio_mfcc(mfcc);
del_fvec(mfcc_out);
beach:
examples_common_del();
return ret;
}
Please help to obtain same result of Librosa or suggest any C++ library do this well.
Thanks
This might be what you are looking for: C Speech Features
The library is a complete port of python_speech_features to C and according to the documentation, you should be able to use it in a C++ projects. The results will not be the same of Librosa, here is why but you should be able to work with them.

Distortion from output Audio Unit

I am hearing a very loud and harsh distortion sound when I run this simple application. I am simply instantiating a default output unit and assign a render callback. And letting the program run in the runloop. I have detected no errors from Core Audio and everything works as usual except for this distortion.
#import <AudioToolbox/AudioToolbox.h>
OSStatus render1(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData)
{
return noErr;
}
int main(int argc, const char * argv[]) {
AudioUnit timerAU;
UInt32 propsize = 0;
AudioComponentDescription outputUnitDesc;
outputUnitDesc.componentType = kAudioUnitType_Output;
outputUnitDesc.componentSubType = kAudioUnitSubType_DefaultOutput;
outputUnitDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
outputUnitDesc.componentFlags = 0;
outputUnitDesc.componentFlagsMask = 0;
//Get RemoteIO AU from Audio Unit Component Manager
AudioComponent outputComp = AudioComponentFindNext(NULL, &outputUnitDesc);
if (outputComp == NULL) exit (-1);
CheckError(AudioComponentInstanceNew(outputComp, &timerAU), "comp");
//Set up render callback function for the RemoteIO AU.
AURenderCallbackStruct renderCallbackStruct;
renderCallbackStruct.inputProc = render1;
renderCallbackStruct.inputProcRefCon = nil;//(__bridge void *)(self);
propsize = sizeof(renderCallbackStruct);
CheckError(AudioUnitSetProperty(timerAU,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Global,
0,
&renderCallbackStruct,
propsize), "set render");
CheckError(AudioUnitInitialize(timerAU), "init");
// tickMethod = completion;
CheckError(AudioOutputUnitStart(timerAU), "start");
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1000, false);
}
Your question does not seem complete. I don't know about the side effects of silencing the output noise which is probably just undefined behavior. I also don't know what your code would serve for as such. There is an unfinished render callback on the kAudioUnitSubType_DefaultOutput which does nothing (it is not generating silence!). I know for two ways of silencing it.
In the callback the ioData buffers have to be explicitly filled with zeroes, because there's no guarantee they will be initialized empty:
Float32 * lBuffer0;
Float32 * lBuffer1;
lBuffer0 = (Float32 *)ioData->mBuffers[0].mData;
lBuffer1 = (Float32 *)ioData->mBuffers[1].mData;
memset(lBuffer0, 0, inNumberFrames*sizeof(Float32));
memset(lBuffer1, 0, inNumberFrames*sizeof(Float32));
Other possibility is to leave the unfinished callback as it is, but declare the timerAU to be of outputUnitDesc.componentSubType = kAudioUnitSubType_HALOutput; instead of
outputUnitDesc.componentSubType = kAudioUnitSubType_DefaultOutput;
and explicity disable I/O before setting the render callback by means of following code:
UInt32 lEnableIO = 0;
CheckError(AudioUnitSetProperty(timerAU,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
0, //output element
&lEnableIO,
sizeof(lEnableIO)),
"couldn't disable output");
I would strongly encourage into studying thoroughly the CoreAudio API and understanding how to set up an audio unit. This is crucial in understanding the matter. I've seen in your code a comment mentioning a RemoteIO AU. There is nothing like a RemoteIO AU in OSX. In case you're attempting a port from iOS code, please try learning the differences. They are well documented.

Setting volumes for multiple streams using Media Foundation

I'm providing audio code for an application that will have multiple streams of audio being played back at the same time. I'm a bit confused by all of the different options, and there are some specific things that I don't quite understand.
I am using the IAudioClient calls to get and set volumes. Is that the best way to get volumes for multiple streams?
It appears that I have to call IAudioClient::Initialize. This function requires a WAVEFORMATEX structure. Are any parameters from that other than the number of channels used in volume setting? Also, it appears that Initialize can only be used once, and volume setting and reading happens many times. Should I save the reference to the IAudioClient and use it each time, or can I release it each time I get or set a volume?
How do I differentiate between two streams being played on the same device (endpoint)?
Here's the code that sets the volume (with the usual checks to make sure each call succeeded eliminated to save space):
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&DeviceEnumerator));
hr = DeviceEnumerator->GetDevice((wchar_t *)currentPlaybackDevice.id, &pPlaybackDevice);
hr = pPlaybackDevice->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void **>(&pPlaybackClient));
hr = pPlaybackClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, 0, 0, &pWaveFormat, 0);
hr = pPlaybackClient->GetService(__uuidof(IAudioStreamVolume), (void **)&pStreamVolume);
hr = pStreamVolume->GetChannelCount(&channels);
for(UINT32 i = 0; i < channels; i++)
chanVolumes[i] = playbackLevel;
hr = pStreamVolume->SetAllVolumes(channels, chanVolumes);
Number of channels is irrelevant to volume. T adjust volume you need to obtain interfaces IAudioStreamVolume, IChannelAudioVolume. See MSDN writes:
The IAudioStreamVolume interface enables a client to control and
monitor the volume levels for all of the channels in an audio stream.
The client obtains a reference to the IAudioStreamVolume interface on
a stream object by calling the IAudioClient::GetService method with
parameter riid set to REFIID IID_IAudioStreamVolume.
Here is the code snippet for you. It plays synthesized sine wave at louder volume for a few seconds, then continues with updated volume to keep playing quietly.
#define _USE_MATH_DEFINES
#include <math.h>
#include <mmdeviceapi.h>
#include <audioclient.h>
#define _A ATLASSERT
#define __C ATLENSURE_SUCCEEDED
#define __D ATLENSURE_THROW
int _tmain(int argc, _TCHAR* argv[])
{
__C(CoInitialize(NULL));
CComPtr<IMMDeviceEnumerator> pMmDeviceEnumerator;
__C(pMmDeviceEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator)));
CComPtr<IMMDevice> pMmDevice;
__C(pMmDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &pMmDevice));
CComPtr<IAudioClient> pAudioClient;
__C(pMmDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (VOID**) &pAudioClient));
CComHeapPtr<WAVEFORMATEX> pWaveFormatEx;
__C(pAudioClient->GetMixFormat(&pWaveFormatEx));
static const REFERENCE_TIME g_nBufferTime = 60 * 1000 * 10000i64; // 1 minute
__C(pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, g_nBufferTime, 0, pWaveFormatEx, NULL));
#pragma region Data
CComPtr<IAudioRenderClient> pAudioRenderClient;
__C(pAudioClient->GetService(__uuidof(IAudioRenderClient), (VOID**) &pAudioRenderClient));
UINT32 nSampleCount = (UINT32) (g_nBufferTime / (1000 * 10000i64) * pWaveFormatEx->nSamplesPerSec) / 2;
_A(pWaveFormatEx->wFormatTag == WAVE_FORMAT_EXTENSIBLE);
const WAVEFORMATEXTENSIBLE* pWaveFormatExtensible = (const WAVEFORMATEXTENSIBLE*) (const WAVEFORMATEX*) pWaveFormatEx;
_A(pWaveFormatExtensible->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT);
// ASSU: Mixing format is IEEE Float PCM
BYTE* pnData = NULL;
__C(pAudioRenderClient->GetBuffer(nSampleCount, &pnData));
FLOAT* pfFloatData = (FLOAT*) pnData;
for(UINT32 nSampleIndex = 0; nSampleIndex < nSampleCount; nSampleIndex++)
for(WORD nChannelIndex = 0; nChannelIndex < pWaveFormatEx->nChannels; nChannelIndex++)
pfFloatData[nSampleIndex * pWaveFormatEx->nChannels + nChannelIndex] = sin(1000.0f * nSampleIndex / pWaveFormatEx->nSamplesPerSec * 2 * M_PI);
__C(pAudioRenderClient->ReleaseBuffer(nSampleCount, 0));
#pragma endregion
CComPtr<ISimpleAudioVolume> pSimpleAudioVolume;
__C(pAudioClient->GetService(__uuidof(ISimpleAudioVolume), (VOID**) &pSimpleAudioVolume));
__C(pSimpleAudioVolume->SetMasterVolume(0.50f, NULL));
_tprintf(_T("Playing Loud\n"));
__C(pAudioClient->Start());
Sleep(5 * 1000);
_tprintf(_T("Playing Quiet\n"));
__C(pSimpleAudioVolume->SetMasterVolume(0.10f, NULL));
Sleep(15 * 1000);
// NOTE: We don't care for termination crash
return 0;
}

Sending a specific SCSI command to a SCSI device in Windows

Does windows have specific interface by which I can send a specific scsi command such Inquiry to scsi device ? I searched the net, found passing reference to SCSI Pass Through interface. But Its very Vague.
Is there any documentation for that API on how to use it??
#include <iostream>
#include <windows.h>
#include <winioctl.h>
#define ULONG_PTR ULONG
#include <ntddscsi.h> //from SDK
#include <spti.h> //from DDK
using namespace std;
int demo()
{
HANDLE hDisk;
SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sptdwb;
ULONG length = 0;
DWORD bytesReturn;
BYTE bufDataRead[64*1024+10];
int iRet;
hDisk = CreateFile(path,GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,OPEN_EXISTING,0,NULL
);
if (hDisk ==INVALID_HANDLE_VALUE) {
return 0;
}
ZeroMemory(&sptdwb, sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER));
sptdwb.sptd.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
sptdwb.sptd.PathId = 0;
sptdwb.sptd.TargetId = 1;
sptdwb.sptd.Lun = 0;
sptdwb.sptd.CdbLength = 6;
sptdwb.sptd.DataIn = SCSI_IOCTL_DATA_IN;
sptdwb.sptd.SenseInfoLength = 24;
sptdwb.sptd.DataTransferLength = 8;
sptdwb.sptd.TimeOutValue = 2;
sptdwb.sptd.DataBuffer = bufDataRead;
sptdwb.sptd.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER,ucSenseBuf);
sptdwb.sptd.Cdb[0] = 0x12;
sptdwb.sptd.Cdb[1] = 0x00;
sptdwb.sptd.Cdb[2] = 0x00;
sptdwb.sptd.Cdb[3] = 0x00;
sptdwb.sptd.Cdb[4] = 0xFF;
sptdwb.sptd.Cdb[5] = 0x00;
length = sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
iRet = DeviceIoControl(hDisk,
IOCTL_SCSI_PASS_THROUGH_DIRECT,
&sptdwb,
length,
&sptdwb,
length,
&bytesReturn,
NULL);
if (0 == iRet) {
printf("inquiry fail");
return 0;
} else {
//Check returned data in sptdwb.sptd.DataBuffer.
}
return 0;
}
SCSI covers a vast amount of ground. Are you talking to a CD/DVD/Disk/Tape/Scanner or what.
For CD/DVD the best (and only) free reference for setup/read/write commands are to be found here: http://www.t10.org/drafts.htm
Re SPTI, there is some very basic documentation in the old 'Programmers guide to SCSI'. There is an article on an ASPI -> SPTI converter that can be found on the DDJ web site.
Bear in mind that SPTI is simply an API, it imposes nor knows anything about SCSI message content or format.
Brian Sawert, Addison Wesley 1998.
You can send SCSI commands to the SCSI Port driver by sending it an IRP_MJ_SCSI IRP, see http://msdn.microsoft.com/en-us/library/ff565387(VS.85).aspx. However, you will have to construct the SCSI CBD yourself, and I have yet to find a document which describes it.
Anymore, the SCSI commands are broken down into a number of specs. The INQUIRY command is in the SPC spec, while device type specific commands are broken down into several specs (i.e. block, ses, ...).

Resources