better file format? + better silence chunks
This commit is contained in:
parent
2d8000b023
commit
3a4784bdea
@ -3,6 +3,16 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "opusfilewriter.h"
|
#include "opusfilewriter.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
uint8_t header[16] = 'DEMOPUSHEADER_V2'
|
||||||
|
uint32_t sampleRate
|
||||||
|
uint64_t samples
|
||||||
|
|
||||||
|
while True:
|
||||||
|
uint64_t samplesOfs
|
||||||
|
uint32_t length
|
||||||
|
uint8_t data[length]
|
||||||
|
*/
|
||||||
|
|
||||||
int opus_stream_write(void *user_data, const unsigned char *ptr, opus_int32 len)
|
int opus_stream_write(void *user_data, const unsigned char *ptr, opus_int32 len)
|
||||||
{
|
{
|
||||||
@ -29,6 +39,7 @@ OpusFileWriter::OpusFileWriter()
|
|||||||
OpusFileWriter::~OpusFileWriter()
|
OpusFileWriter::~OpusFileWriter()
|
||||||
{
|
{
|
||||||
assert(!m_Enc);
|
assert(!m_Enc);
|
||||||
|
assert(!m_OutFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpusFileWriter::Init(const char* file, uint32_t sampleRate)
|
void OpusFileWriter::Init(const char* file, uint32_t sampleRate)
|
||||||
@ -44,16 +55,16 @@ void OpusFileWriter::Init(const char* file, uint32_t sampleRate)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t customHeader[16] = {'D', 'E', 'M', 'O', 'P', 'U', 'S', 'H', 'E', 'A', 'D', 'E', 'R', '_', 'V', '1'};
|
uint8_t customHeader[16] = {'D', 'E', 'M', 'O', 'P', 'U', 'S', 'H', 'E', 'A', 'D', 'E', 'R', '_', 'V', '2'};
|
||||||
fwrite(customHeader, sizeof(customHeader), 1, m_OutFile);
|
fwrite(customHeader, sizeof(customHeader), 1, m_OutFile);
|
||||||
|
|
||||||
uint8_t header = HEADER_TYPE_INFO;
|
|
||||||
fwrite(&header, sizeof(header), 1, m_OutFile);
|
|
||||||
m_InfoStartPos = ftell(m_OutFile);
|
m_InfoStartPos = ftell(m_OutFile);
|
||||||
fwrite(&m_SampleRate, sizeof(m_SampleRate), 1, m_OutFile);
|
fwrite(&m_SampleRate, sizeof(m_SampleRate), 1, m_OutFile);
|
||||||
fwrite(&m_Samples, sizeof(m_Samples), 1, m_OutFile);
|
fwrite(&m_Samples, sizeof(m_Samples), 1, m_OutFile);
|
||||||
|
|
||||||
m_Comments = ope_comments_create();
|
m_Comments = ope_comments_create();
|
||||||
|
|
||||||
|
SwitchState(STATE_SILENCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpusFileWriter::Close()
|
void OpusFileWriter::Close()
|
||||||
@ -61,8 +72,7 @@ void OpusFileWriter::Close()
|
|||||||
if(!m_OutFile)
|
if(!m_OutFile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SwitchState(HEADER_TYPE_INFO);
|
SwitchState(STATE_DONE);
|
||||||
SwitchState(HEADER_TYPE_DONE);
|
|
||||||
|
|
||||||
ope_comments_destroy(m_Comments);
|
ope_comments_destroy(m_Comments);
|
||||||
m_Enc = nullptr;
|
m_Enc = nullptr;
|
||||||
@ -79,29 +89,27 @@ void OpusFileWriter::SwitchState(int newState)
|
|||||||
if(m_State == newState)
|
if(m_State == newState)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(m_State == HEADER_TYPE_SILENCE)
|
if(m_State == STATE_SILENCE)
|
||||||
{
|
{
|
||||||
fwrite(&m_SilenceSamples, sizeof(m_SilenceSamples), 1, m_OutFile);
|
fwrite(&m_Samples, sizeof(m_Samples), 1, m_OutFile);
|
||||||
}
|
}
|
||||||
else if(m_State == HEADER_TYPE_OPUS)
|
else if(m_State == STATE_OPUS)
|
||||||
{
|
{
|
||||||
ope_encoder_drain(m_Enc);
|
ope_encoder_drain(m_Enc);
|
||||||
ope_encoder_destroy(m_Enc);
|
ope_encoder_destroy(m_Enc);
|
||||||
m_Enc = nullptr;
|
m_Enc = nullptr;
|
||||||
|
|
||||||
m_DataEndPos = ftell(m_OutFile);
|
long int dataEndPos = ftell(m_OutFile);
|
||||||
fseek(m_OutFile, m_LengthStartPos, SEEK_SET);
|
fseek(m_OutFile, m_LengthStartPos, SEEK_SET);
|
||||||
uint64_t dataLen = m_DataEndPos - (m_LengthStartPos + sizeof(uint64_t));
|
uint32_t dataLen = dataEndPos - (m_LengthStartPos + sizeof(uint32_t));
|
||||||
fwrite(&dataLen, sizeof(dataLen), 1, m_OutFile);
|
fwrite(&dataLen, sizeof(dataLen), 1, m_OutFile);
|
||||||
fseek(m_OutFile, m_DataEndPos, SEEK_SET);
|
fseek(m_OutFile, dataEndPos, SEEK_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(newState == HEADER_TYPE_OPUS)
|
if(newState == STATE_OPUS)
|
||||||
{
|
{
|
||||||
uint8_t header = HEADER_TYPE_OPUS;
|
|
||||||
fwrite(&header, sizeof(header), 1, m_OutFile);
|
|
||||||
m_LengthStartPos = ftell(m_OutFile);
|
m_LengthStartPos = ftell(m_OutFile);
|
||||||
uint64_t dataLen = 0;
|
uint32_t dataLen = 0;
|
||||||
fwrite(&dataLen, sizeof(dataLen), 1, m_OutFile);
|
fwrite(&dataLen, sizeof(dataLen), 1, m_OutFile);
|
||||||
|
|
||||||
int error;
|
int error;
|
||||||
@ -109,15 +117,10 @@ void OpusFileWriter::SwitchState(int newState)
|
|||||||
m_Enc = ope_encoder_create_callbacks(&opus_callbacks, (void *)this, m_Comments, m_SampleRate, 1, 0, &error);
|
m_Enc = ope_encoder_create_callbacks(&opus_callbacks, (void *)this, m_Comments, m_SampleRate, 1, 0, &error);
|
||||||
assert(error == 0);
|
assert(error == 0);
|
||||||
}
|
}
|
||||||
else if(newState == HEADER_TYPE_SILENCE)
|
else if(newState == STATE_SILENCE)
|
||||||
{
|
{
|
||||||
m_SilenceStart = m_Samples;
|
|
||||||
m_SilenceSamples = 0;
|
|
||||||
|
|
||||||
uint8_t header = HEADER_TYPE_SILENCE;
|
|
||||||
fwrite(&header, sizeof(header), 1, m_OutFile);
|
|
||||||
}
|
}
|
||||||
else if(newState == HEADER_TYPE_INFO)
|
else if(newState == STATE_DONE)
|
||||||
{
|
{
|
||||||
long int backup = ftell(m_OutFile);
|
long int backup = ftell(m_OutFile);
|
||||||
fseek(m_OutFile, m_InfoStartPos, SEEK_SET);
|
fseek(m_OutFile, m_InfoStartPos, SEEK_SET);
|
||||||
@ -125,11 +128,6 @@ void OpusFileWriter::SwitchState(int newState)
|
|||||||
fwrite(&m_Samples, sizeof(m_Samples), 1, m_OutFile);
|
fwrite(&m_Samples, sizeof(m_Samples), 1, m_OutFile);
|
||||||
fseek(m_OutFile, backup, SEEK_SET);
|
fseek(m_OutFile, backup, SEEK_SET);
|
||||||
}
|
}
|
||||||
else if(newState == HEADER_TYPE_DONE)
|
|
||||||
{
|
|
||||||
uint8_t header = HEADER_TYPE_DONE;
|
|
||||||
fwrite(&header, sizeof(header), 1, m_OutFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_State = newState;
|
m_State = newState;
|
||||||
}
|
}
|
||||||
@ -150,7 +148,7 @@ void OpusFileWriter::WriteSamples(const int16_t* samples, uint32_t numSamples)
|
|||||||
if(!m_OutFile)
|
if(!m_OutFile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SwitchState(HEADER_TYPE_OPUS);
|
SwitchState(STATE_OPUS);
|
||||||
|
|
||||||
ope_encoder_write(m_Enc, samples, numSamples);
|
ope_encoder_write(m_Enc, samples, numSamples);
|
||||||
m_Samples += numSamples;
|
m_Samples += numSamples;
|
||||||
@ -162,8 +160,7 @@ void OpusFileWriter::PadSilence(uint64_t milliseconds)
|
|||||||
if(!m_OutFile || m_Samples >= numSamples)
|
if(!m_OutFile || m_Samples >= numSamples)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SwitchState(HEADER_TYPE_SILENCE);
|
SwitchState(STATE_SILENCE);
|
||||||
|
|
||||||
m_Samples = numSamples;
|
m_Samples = numSamples;
|
||||||
m_SilenceSamples = m_Samples - m_SilenceStart;
|
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,9 @@
|
|||||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
HEADER_TYPE_NONE = 0,
|
STATE_DONE = 0,
|
||||||
HEADER_TYPE_INFO = 0x01,
|
STATE_SILENCE = 1,
|
||||||
HEADER_TYPE_OPUS = 0x02,
|
STATE_OPUS = 2
|
||||||
HEADER_TYPE_SILENCE = 0x03,
|
|
||||||
HEADER_TYPE_DONE = 0x04
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class OpusFileWriter
|
class OpusFileWriter
|
||||||
@ -30,13 +28,10 @@ public:
|
|||||||
int opus_stream_close();
|
int opus_stream_close();
|
||||||
private:
|
private:
|
||||||
FILE *m_OutFile = nullptr;
|
FILE *m_OutFile = nullptr;
|
||||||
int m_State = HEADER_TYPE_NONE;
|
int m_State = STATE_DONE;
|
||||||
long int m_InfoStartPos;
|
long int m_InfoStartPos;
|
||||||
long int m_LengthStartPos;
|
long int m_LengthStartPos;
|
||||||
long int m_DataEndPos;
|
long int m_SilenceStartPos;
|
||||||
|
|
||||||
uint64_t m_SilenceStart = 0;
|
|
||||||
uint64_t m_SilenceSamples = 0;
|
|
||||||
|
|
||||||
OggOpusComments *m_Comments = nullptr;
|
OggOpusComments *m_Comments = nullptr;
|
||||||
OggOpusEnc *m_Enc = nullptr;
|
OggOpusEnc *m_Enc = nullptr;
|
||||||
|
@ -198,7 +198,7 @@ void VoiceDataWriter::EndCommandPacket(const PacketTrailingBits& trailingBits)
|
|||||||
else if(m_isSilenced)
|
else if(m_isSilenced)
|
||||||
{
|
{
|
||||||
m_isSilenced = false;
|
m_isSilenced = false;
|
||||||
m_silence.back().second = m_silenceTicks - m_silenceTicksStart;
|
m_silence.back().second = m_silenceTicks;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& state : m_playerVoiceStates)
|
for(auto& state : m_playerVoiceStates)
|
||||||
|
32
demopus.py
Normal file
32
demopus.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
|
||||||
|
with open(sys.argv[1], 'rb') as fp:
|
||||||
|
data = fp.read()
|
||||||
|
|
||||||
|
ofs = 16
|
||||||
|
counter = 0
|
||||||
|
|
||||||
|
srate = struct.unpack('I', data[ofs:ofs+4])[0]
|
||||||
|
ofs += 4
|
||||||
|
samples = struct.unpack('Q', data[ofs:ofs+8])[0]
|
||||||
|
ofs += 8
|
||||||
|
print(f'srate: {srate} | samples: {samples}\n')
|
||||||
|
|
||||||
|
while ofs < len(data):
|
||||||
|
sampleOfs = struct.unpack('Q', data[ofs:ofs+8])[0]
|
||||||
|
ofs += 8
|
||||||
|
|
||||||
|
if ofs >= len(data):
|
||||||
|
print(f'#END (0) @ {sampleOfs}')
|
||||||
|
break
|
||||||
|
|
||||||
|
dlen = struct.unpack('I', data[ofs:ofs+4])[0]
|
||||||
|
ofs += 4
|
||||||
|
|
||||||
|
with open(f'{sampleOfs}.opus', 'wb') as fp:
|
||||||
|
fp.write(data[ofs:ofs+dlen])
|
||||||
|
ofs += dlen
|
||||||
|
|
||||||
|
counter += 1
|
||||||
|
print(f'#{counter} ({dlen}) @ {sampleOfs}')
|
Loading…
Reference in New Issue
Block a user