-
Notifications
You must be signed in to change notification settings - Fork 141
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add TestSender
- Loading branch information
Showing
14 changed files
with
840 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
#include "ac3encoder.h" | ||
|
||
#include <mfapi.h> | ||
#include <mferror.h> | ||
|
||
template<class T> | ||
void SafeRelease(T **ppT) | ||
{ | ||
if (*ppT) { | ||
(*ppT)->Release(); | ||
*ppT = NULL; | ||
} | ||
} | ||
|
||
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)); | ||
} | ||
|
||
// 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()) { | ||
ReleaseSample(sample); | ||
} | ||
} | ||
|
||
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); | ||
|
||
SafeRelease(&pSample); | ||
SafeRelease(&pBuffer); | ||
} | ||
|
||
void Ac3Encoder::ReleaseSample(IMFSample *sample) | ||
{ | ||
SafeRelease(&sample); | ||
} | ||
|
||
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: | ||
SafeRelease(&pBufferOut); | ||
SafeRelease(&pSampleOut); | ||
|
||
return pSample; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#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 ReleaseSample(IMFSample *sample); | ||
|
||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.