Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Scream/Scream.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@
<FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="ac3encoder.cpp" />
<ClCompile Include="adapter.cpp" />
<ClCompile Include="common.cpp" />
<ClCompile Include="hw.cpp" />
Expand All @@ -237,6 +238,7 @@
<ClCompile Include="savedata.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="ac3encoder.h" />
<ClInclude Include="common.h" />
<ClInclude Include="hw.h" />
<ClInclude Include="ivshmemsavedata.h" />
Expand All @@ -246,6 +248,7 @@
<ClInclude Include="minwave.h" />
<ClInclude Include="netiodef.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="rtpheader.h" />
<ClInclude Include="savedata.h" />
<ClInclude Include="scream.h" />
<ClInclude Include="toptable.h" />
Expand Down
9 changes: 9 additions & 0 deletions Scream/Scream.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@
<ClCompile Include="ivshmemsavedata.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ac3encoder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="common.h">
Expand Down Expand Up @@ -92,6 +95,12 @@
<ClInclude Include="ivshmemsavedata.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ac3encoder.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="rtpheader.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="scream.rc">
Expand Down
211 changes: 211 additions & 0 deletions Scream/ac3encoder.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
#include "stdafx.h"
#include "ac3encoder.h"

#include <mfapi.h>
#include <mferror.h>

#pragma comment(lib, "mfplat.lib")
#pragma comment(lib, "mfuuid.lib")

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

Ac3Encoder::Ac3Encoder(UINT32 sampleRate,
UINT32 numChannels) :
m_sampleRate(sampleRate),
m_numChannels(numChannels)
{
Initialize(m_sampleRate, m_numChannels);
}

Ac3Encoder::~Ac3Encoder()
{
SafeRelease(&m_transform);
SafeRelease(&m_inputType);
SafeRelease(&m_outputType);
}

HRESULT Ac3Encoder::Initialize(UINT32 sampleRate, UINT32 numChannels)
{
m_sampleRate = sampleRate;
m_numChannels = numChannels;

SafeRelease(&m_transform);
SafeRelease(&m_inputType);
SafeRelease(&m_outputType);

// Look for a encoder.
MFT_REGISTER_TYPE_INFO outInfo;
outInfo.guidMajorType = MFMediaType_Audio;
outInfo.guidSubtype = MFAudioFormat_Dolby_AC3;
CLSID *clsids = nullptr; // Pointer to an array of CLISDs.
UINT32 clsidsSize = 0; // Size of the array.
auto hr = MFTEnum(MFT_CATEGORY_AUDIO_ENCODER,
0, // Flags
NULL, // Input type to match.
&outInfo, // Output type to match.
NULL, // Attributes to match. (None.)
&clsids, // Receives a pointer to an array of CLSIDs.
&clsidsSize // Receives the size of the array.
);

if (SUCCEEDED(hr) && clsidsSize == 0) {
hr = MF_E_TOPO_CODEC_NOT_FOUND;
}

// Create the MFT decoder
if (SUCCEEDED(hr)) {
hr = CoCreateInstance(clsids[0], NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_transform));
}

if (!SUCCEEDED(hr)) {
return hr;
}

// Create and set output type
MFCreateMediaType(&m_outputType);
m_outputType->SetGUID(MF_MT_MAJOR_TYPE, outInfo.guidMajorType);
m_outputType->SetGUID(MF_MT_SUBTYPE, outInfo.guidSubtype);
m_outputType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, sampleRate);
m_outputType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, numChannels);
m_outputType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, m_bitrateKbps*1000/8);
hr = m_transform->SetOutputType(0, m_outputType , 0);

MFCreateMediaType(&m_inputType);
m_inputType->SetGUID(MF_MT_MAJOR_TYPE, outInfo.guidMajorType);
m_inputType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
m_inputType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, 16);
m_inputType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, sampleRate);
m_inputType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, numChannels);
m_inputType->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4);
m_inputType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, sampleRate*4);
hr = m_transform->SetInputType(0, m_inputType , 0);

return hr;
}

void Ac3Encoder::SetBitrate(UINT32 kbps)
{
if (m_bitrateKbps == kbps) {
return;
}

m_bitrateKbps = kbps;
Initialize(m_sampleRate, m_numChannels);
}

IMFSample* Ac3Encoder::Process(void *inBuffer, UINT32 inSize)
{
// Feed inpud data
ProcessInput(inBuffer, inSize);

// Check if we have a complete AC3 frame ready for output.
IMFSample *outSample = ProcessOutput();
// Once we get an outSample, we have to process output again to put the
// transform back in accepting state.
if (outSample) {
while (auto sample = ProcessOutput()) {
sample->Release();
}
}

return outSample;
}

void Ac3Encoder::ProcessInput(void *inSamples, UINT32 inSize)
{
// Create buffer
IMFMediaBuffer *pBuffer = NULL;
auto hr = MFCreateMemoryBuffer(inSize, &pBuffer);

// Copy sample data to buffer
BYTE *pMem = NULL;
if (SUCCEEDED(hr)) {
hr = pBuffer->Lock(&pMem, NULL, NULL);
}

if (SUCCEEDED(hr)) {
memcpy(pMem, inSamples, inSize);
}
pBuffer->Unlock();

// Set the data length of the buffer.
if (SUCCEEDED(hr)) {
hr = pBuffer->SetCurrentLength(inSize);
}

// Create media sample and add the buffer to the sample.
IMFSample *pSample = NULL;
if (SUCCEEDED(hr)) {
hr = MFCreateSample(&pSample);
}
if (SUCCEEDED(hr)) {
hr = pSample->AddBuffer(pBuffer);
}

hr = m_transform->ProcessInput(0, pSample, 0);

pSample->Release();
pBuffer->Release();
}

void Ac3Encoder::Drain()
{
m_transform->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0);
}

IMFSample* Ac3Encoder::ProcessOutput()
{
IMFSample* pSample = nullptr;
MFT_OUTPUT_DATA_BUFFER mftOutputData = { 0, nullptr, 0, nullptr };
MFT_OUTPUT_STREAM_INFO mftStreamInfo = { 0, 0, 0 };
IMFMediaBuffer* pBufferOut = nullptr;
IMFSample* pSampleOut = nullptr;

// Get output info
HRESULT hr = m_transform->GetOutputStreamInfo(0, &mftStreamInfo);
if (FAILED(hr)) {
goto done;
}

// Create the output sample
hr = MFCreateSample(&pSampleOut);
if (FAILED(hr)) {
goto done;
}
// Create buffer and add to output sample
hr = MFCreateMemoryBuffer(mftStreamInfo.cbSize, &pBufferOut);
if (FAILED(hr)) {
goto done;
}
hr = pSampleOut->AddBuffer(pBufferOut);
if (FAILED(hr)) {
goto done;
}

// Generate the output sample
mftOutputData.pSample = pSampleOut;
DWORD dwStatus;
hr = m_transform->ProcessOutput(0, 1, &mftOutputData, &dwStatus);
if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) {
goto done;
}
if (FAILED(hr)) {
goto done;
}

pSample = pSampleOut;
pSample->AddRef();

done:
pBufferOut->Release();
pSampleOut->Release();

return pSample;
}
32 changes: 32 additions & 0 deletions Scream/ac3encoder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#ifndef AC3ENCODER_H
#define AC3ENCODER_H

#include <mftransform.h>

class Ac3Encoder
{
public:
Ac3Encoder(UINT32 sampleRate = 48000,
UINT32 numChannels = 2);
~Ac3Encoder();

HRESULT Initialize(UINT32 sampleRate, UINT32 numChannels);
void SetBitrate(UINT32 kbps);

IMFSample* Process(void *inSamples, UINT32 inSize);

void Drain();

private:
void ProcessInput(void *sampleData, UINT32 size);
IMFSample* ProcessOutput();

UINT32 m_sampleRate = 48000;
UINT32 m_numChannels = 2;
UINT32 m_bitrateKbps = 256;
IMFTransform *m_transform = nullptr; // Pointer to the encoder MFT.
IMFMediaType *m_inputType = nullptr; // Input media type of the encoder.
IMFMediaType *m_outputType = nullptr; // Output media type of the encoder.
};

#endif // AC3ENCODER_H
4 changes: 4 additions & 0 deletions Scream/adapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ PCHAR g_UnicastIPv4;
DWORD g_UnicastPort;
//0 = false, otherwhise it's value is the size in MiB of the IVSHMEM we want to use
UINT8 g_UseIVSHMEM;
UINT8 g_UseRtpAc3;

//-----------------------------------------------------------------------------
// Referenced forward.
Expand Down Expand Up @@ -78,13 +79,15 @@ Routine Description:
UNICODE_STRING unicastIPv4;
DWORD unicastPort = 0;
DWORD useIVSHMEM = 0;
DWORD useRtpAc3 = 0;

RtlZeroMemory(&unicastIPv4, sizeof(UNICODE_STRING));

RTL_QUERY_REGISTRY_TABLE paramTable[] = {
{ NULL, RTL_QUERY_REGISTRY_DIRECT, L"UnicastIPv4", &unicastIPv4, REG_NONE, NULL, 0 },
{ NULL, RTL_QUERY_REGISTRY_DIRECT, L"UnicastPort", &unicastPort, REG_NONE, NULL, 0 },
{ NULL, RTL_QUERY_REGISTRY_DIRECT, L"UseIVSHMEM", &useIVSHMEM, REG_NONE, NULL, 0 },
{ NULL, RTL_QUERY_REGISTRY_DIRECT, L"UseRtpAc3", &useRtpAc3, REG_NONE, NULL, 0 },
{ NULL, 0, NULL, NULL, 0, NULL, 0 }
};

Expand Down Expand Up @@ -164,6 +167,7 @@ Routine Description:
}

g_UseIVSHMEM = (UINT8)useIVSHMEM;
g_UseRtpAc3 = (UINT8)useRtpAc3;

ExFreePool(parametersPath.Buffer);

Expand Down
25 changes: 25 additions & 0 deletions Scream/rtpheader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef RTPHEADER_H
#define RTPHEADER_H

#pragma pack(push, 1)
struct RtpHeader
{
unsigned char cc : 4; /* CSRC count (always 0) */
unsigned char x : 1; /* header extension flag (always 0) */
unsigned char p : 1; /* padding flag (always 0) */
unsigned char v : 2; /* protocol version (always 2) */

unsigned char pt : 7; /* payload type (always 10, meaning L16 linear PCM, 2 channels) */
unsigned char m : 1; /* marker bit (always 0) */

unsigned short seq : 16; /* sequence number (monotonically incrementing, will just wrap) */

// Bytes 4-7
unsigned int ts : 32; /* timestamp of 1st sample in packet, increase by 1 for each 4 bytes sent */

// Bytes 8-11
unsigned int ssrc : 32; /* synchronization source (always 0) */
};
#pragma pack(pop)

#endif // RTPHEADER_H
Loading