mirror of
https://github.com/badaix/snapcast.git
synced 2025-05-10 23:56:43 +02:00
experimental FLAC support
This commit is contained in:
parent
176ed8abc0
commit
d99c3cb9a0
10 changed files with 289 additions and 35 deletions
|
@ -1,9 +1,9 @@
|
|||
VERSION = 0.1
|
||||
CC = /usr/bin/g++
|
||||
CFLAGS = -std=gnu++0x -static-libgcc -static-libstdc++ -Wall -Wno-unused-function -O3 -D_REENTRANT -DVERSION=\"$(VERSION)\" -I..
|
||||
LDFLAGS = -lrt -lpthread -lboost_system -lboost_program_options -lasound -logg -lvorbis -lvorbisenc
|
||||
LDFLAGS = -lrt -lpthread -lboost_system -lboost_program_options -lasound -logg -lvorbis -lvorbisenc -lFLAC
|
||||
|
||||
OBJ = snapClient.o stream.o alsaPlayer.o clientConnection.o timeProvider.o oggDecoder.o pcmDecoder.o controller.o ../message/pcmChunk.o ../common/log.o ../message/sampleFormat.o
|
||||
OBJ = snapClient.o stream.o alsaPlayer.o clientConnection.o timeProvider.o oggDecoder.o pcmDecoder.o flacDecoder.o controller.o ../message/pcmChunk.o ../common/log.o ../message/sampleFormat.o
|
||||
BIN = snapclient
|
||||
|
||||
all: client
|
||||
|
|
|
@ -97,7 +97,7 @@ void Player::start()
|
|||
snd_pcm_sw_params(pcm_handle_, swparams);
|
||||
|
||||
active_ = true;
|
||||
playerThread_ = new thread(&Player::worker, this);
|
||||
playerThread_ = thread(&Player::worker, this);
|
||||
}
|
||||
|
||||
|
||||
|
@ -108,12 +108,10 @@ Player::~Player()
|
|||
|
||||
|
||||
void Player::stop() {
|
||||
active_ = false;
|
||||
if (playerThread_ != NULL)
|
||||
if (active_)
|
||||
{
|
||||
playerThread_->join();
|
||||
delete playerThread_;
|
||||
playerThread_ = NULL;
|
||||
active_ = false;
|
||||
playerThread_.join();
|
||||
}
|
||||
|
||||
if (pcm_handle_ != NULL)
|
||||
|
|
|
@ -26,7 +26,7 @@ private:
|
|||
char *buff_;
|
||||
std::atomic<bool> active_;
|
||||
Stream* stream_;
|
||||
std::thread* playerThread_;
|
||||
std::thread playerThread_;
|
||||
PcmDevice pcmDevice_;
|
||||
};
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <unistd.h>
|
||||
#include "oggDecoder.h"
|
||||
#include "pcmDecoder.h"
|
||||
#include "flacDecoder.h"
|
||||
#include "alsaPlayer.h"
|
||||
#include "timeProvider.h"
|
||||
#include "common/log.h"
|
||||
|
@ -99,6 +100,8 @@ void Controller::worker()
|
|||
decoder_ = new OggDecoder();
|
||||
else if (headerChunk->codec == "pcm")
|
||||
decoder_ = new PcmDecoder();
|
||||
else if (headerChunk->codec == "flac")
|
||||
decoder_ = new FlacDecoder();
|
||||
decoder_->setHeader(headerChunk.get());
|
||||
|
||||
msg::Request timeReq(kTime);
|
||||
|
@ -149,8 +152,8 @@ void Controller::worker()
|
|||
delete decoder_;
|
||||
decoder_ = NULL;
|
||||
logO << "done" << endl;
|
||||
if (active_)
|
||||
usleep(500*1000);
|
||||
for (size_t n=0; (n<10) && active_; ++n)
|
||||
usleep(100*1000);
|
||||
}
|
||||
}
|
||||
logD << "Thread stopped\n";
|
||||
|
|
187
client/flacDecoder.cpp
Normal file
187
client/flacDecoder.cpp
Normal file
|
@ -0,0 +1,187 @@
|
|||
#include "flacDecoder.h"
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include <FLAC/stream_decoder.h>
|
||||
#include "common/log.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
static FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
|
||||
static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
|
||||
static void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
|
||||
static void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
|
||||
|
||||
static FLAC__uint64 total_samples = 0;
|
||||
static unsigned sample_rate = 0;
|
||||
static unsigned channels = 0;
|
||||
static unsigned bps = 0;
|
||||
static msg::Header* flacHeader = NULL;
|
||||
static msg::PcmChunk* flacChunk = NULL;
|
||||
static FLAC__StreamDecoder *decoder = 0;
|
||||
|
||||
|
||||
FlacDecoder::FlacDecoder() : Decoder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
FlacDecoder::~FlacDecoder()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool FlacDecoder::decode(msg::PcmChunk* chunk)
|
||||
{
|
||||
flacChunk = chunk;
|
||||
//logO << "Decode start: " << chunk->payloadSize << endl;
|
||||
// flacChunk->payload = (char*)realloc(flacChunk->payload, chunk->payloadSize);
|
||||
// memcpy(flacChunk->payload, chunk->payload, chunk->payloadSize);
|
||||
// flacChunk->payloadSize = chunk->payloadSize;
|
||||
FLAC__stream_decoder_process_single(decoder);
|
||||
FLAC__stream_decoder_process_single(decoder);
|
||||
//logO << "Decode end\n" << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool FlacDecoder::setHeader(msg::Header* chunk)
|
||||
{
|
||||
flacHeader = chunk;
|
||||
FLAC__bool ok = true;
|
||||
FLAC__StreamDecoderInitStatus init_status;
|
||||
|
||||
if((decoder = FLAC__stream_decoder_new()) == NULL) {
|
||||
fprintf(stderr, "ERROR: allocating decoder\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// (void)FLAC__stream_decoder_set_md5_checking(decoder, true);
|
||||
|
||||
init_status = FLAC__stream_decoder_init_stream(decoder, read_callback, NULL, NULL, NULL, NULL, write_callback, metadata_callback, error_callback, this);
|
||||
|
||||
// init_status = FLAC__stream_decoder_init_file(decoder, argv[1], write_callback, metadata_callback, error_callback, fout);
|
||||
if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
|
||||
fprintf(stderr, "ERROR: initializing decoder: %s\n", FLAC__StreamDecoderInitStatusString[init_status]);
|
||||
ok = false;
|
||||
}
|
||||
// FLAC__stream_decoder_process_until_end_of_stream(decoder);
|
||||
FLAC__stream_decoder_process_until_end_of_metadata(decoder);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
|
||||
{
|
||||
if (flacHeader != NULL)
|
||||
{
|
||||
*bytes = flacHeader->payloadSize;
|
||||
memcpy(buffer, flacHeader->payload, *bytes);
|
||||
flacHeader = NULL;
|
||||
}
|
||||
else if (flacChunk != NULL)
|
||||
{
|
||||
//logO << "Read: " << *bytes << "\t" << flacChunk->payloadSize << "\n";
|
||||
if (*bytes > flacChunk->payloadSize)
|
||||
*bytes = flacChunk->payloadSize;
|
||||
|
||||
if (flacChunk->payloadSize == 0)
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
|
||||
|
||||
memcpy(buffer, flacChunk->payload, *bytes);
|
||||
memmove(flacChunk->payload, flacChunk->payload + *bytes, flacChunk->payloadSize - *bytes);
|
||||
flacChunk->payloadSize = flacChunk->payloadSize - *bytes;
|
||||
flacChunk->payload = (char*)realloc(flacChunk->payload, flacChunk->payloadSize);
|
||||
//logO << "Read end\n";
|
||||
// return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
|
||||
}
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
|
||||
{
|
||||
//logO << "Write start\n";
|
||||
(void)decoder;
|
||||
|
||||
if(channels != 2 || bps != 16) {
|
||||
fprintf(stderr, "ERROR: this example only supports 16bit stereo streams\n");
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||
}
|
||||
if(frame->header.channels != 2) {
|
||||
fprintf(stderr, "ERROR: This frame contains %d channels (should be 2)\n", frame->header.channels);
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||
}
|
||||
if(buffer [0] == NULL) {
|
||||
fprintf(stderr, "ERROR: buffer [0] is NULL\n");
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||
}
|
||||
if(buffer [1] == NULL) {
|
||||
fprintf(stderr, "ERROR: buffer [1] is NULL\n");
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||
}
|
||||
|
||||
if (flacChunk != NULL)
|
||||
{
|
||||
size_t bytes = frame->header.blocksize * 4;
|
||||
//logO << "blocksize: " << frame->header.blocksize << "\tframe_number: " << frame->header.number.frame_number << "\tsample_number: " << frame->header.number.sample_number << "\n";
|
||||
//logO << "Write: " << bytes << "\n";
|
||||
//flacChunk->payloadSize = 0;
|
||||
flacChunk->payload = (char*)realloc(flacChunk->payload, flacChunk->payloadSize + bytes);
|
||||
for(size_t i = 0; i < frame->header.blocksize; i++)
|
||||
{
|
||||
memcpy(flacChunk->payload + flacChunk->payloadSize + 4*i, (char*)(buffer[0] + i), 2);
|
||||
memcpy(flacChunk->payload + flacChunk->payloadSize + 4*i+2, (char*)(buffer[1] + i), 2);
|
||||
//logO << 4*i+2 << "\t" << bytes << "\n";
|
||||
}
|
||||
flacChunk->payloadSize += bytes;
|
||||
//logO << "Write end: " << flacChunk->payloadSize << "\n";
|
||||
}
|
||||
|
||||
/* write decoded PCM samples */
|
||||
/* for(i = 0; i < frame->header.blocksize; i++) {
|
||||
if(
|
||||
!write_little_endian_int16(f, (FLAC__int16)buffer[0][i]) || // left channel
|
||||
!write_little_endian_int16(f, (FLAC__int16)buffer[1][i]) // right channel
|
||||
) {
|
||||
fprintf(stderr, "ERROR: write error\n");
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||
}
|
||||
}
|
||||
*/
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
|
||||
{
|
||||
(void)decoder, (void)client_data;
|
||||
|
||||
/* print some stats */
|
||||
if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
|
||||
/* save for later */
|
||||
total_samples = metadata->data.stream_info.total_samples;
|
||||
sample_rate = metadata->data.stream_info.sample_rate;
|
||||
channels = metadata->data.stream_info.channels;
|
||||
bps = metadata->data.stream_info.bits_per_sample;
|
||||
|
||||
logO << "sample rate : " << sample_rate << "Hz\n";
|
||||
logO << "channels : " << channels << "\n";
|
||||
logO << "bits per sample: " << bps << "\n";
|
||||
logO << "total samples : " << total_samples << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
|
||||
{
|
||||
(void)decoder, (void)client_data;
|
||||
fprintf(stderr, "Got error callback: %s\n", FLAC__StreamDecoderErrorStatusString[status]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
18
client/flacDecoder.h
Normal file
18
client/flacDecoder.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef FLAC_DECODER_H
|
||||
#define FLAC_DECODER_H
|
||||
#include "decoder.h"
|
||||
|
||||
|
||||
class FlacDecoder : public Decoder
|
||||
{
|
||||
public:
|
||||
FlacDecoder();
|
||||
virtual ~FlacDecoder();
|
||||
virtual bool decode(msg::PcmChunk* chunk);
|
||||
virtual bool setHeader(msg::Header* chunk);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
VERSION = 0.1
|
||||
CC = /usr/bin/g++
|
||||
CFLAGS = -std=gnu++0x -Wall -Wno-unused-function -O3 -D_REENTRANT -DVERSION=\"$(VERSION)\" -I..
|
||||
LDFLAGS = -lrt -lpthread -lboost_system -lboost_program_options -lvorbis -lvorbisenc -logg
|
||||
LDFLAGS = -lrt -lpthread -lboost_system -lboost_program_options -lvorbis -lvorbisenc -logg -lFLAC
|
||||
|
||||
OBJ = snapServer.o controlServer.o pcmEncoder.o oggEncoder.o serverSession.o ../common/log.o ../message/pcmChunk.o ../message/sampleFormat.o
|
||||
OBJ = snapServer.o controlServer.o flacEncoder.o pcmEncoder.o oggEncoder.o serverSession.o ../common/log.o ../message/pcmChunk.o ../message/sampleFormat.o
|
||||
BIN = snapserver
|
||||
|
||||
all: server
|
||||
|
|
|
@ -5,28 +5,75 @@
|
|||
using namespace std;
|
||||
|
||||
|
||||
FlacEncoder::FlacEncoder(const msg::SampleFormat& format) : Encoder(format)
|
||||
FlacEncoder::FlacEncoder(const msg::SampleFormat& format) : Encoder(format), encoder(0)
|
||||
{
|
||||
headerChunk = new HeaderMessage("flac");
|
||||
initEncoder();
|
||||
}
|
||||
|
||||
|
||||
#define READSIZE 16384
|
||||
|
||||
static FLAC__int32 pcm[READSIZE/*samples*/ * 2/*channels*/];
|
||||
size_t encodedSamples = 0;
|
||||
static msg::PcmChunk* encodedChunk;
|
||||
|
||||
|
||||
msg::Header* FlacEncoder::getHeaderChunk()
|
||||
{
|
||||
return headerChunk;
|
||||
}
|
||||
|
||||
|
||||
double FlacEncoder::encode(msg::PcmChunk* chunk)
|
||||
{
|
||||
return chunk->duration<chronos::msec>().count();
|
||||
logD << "payload: " << chunk->payloadSize << "\tsamples: " << chunk->payloadSize/4 << "\n";
|
||||
int samples = chunk->payloadSize / 4;
|
||||
for(int i=0; i<samples*2/*channels*/; i++)
|
||||
{
|
||||
pcm[i] = (FLAC__int32)(((FLAC__int16)(FLAC__int8)chunk->payload[2*i+1] << 8) | (FLAC__int16)(0x00ff&chunk->payload[2*i]));
|
||||
}
|
||||
FLAC__stream_encoder_process_interleaved(encoder, pcm, samples);
|
||||
|
||||
double res = encodedSamples / ((double)sampleFormat.rate / 1000.);
|
||||
if (encodedSamples > 0)
|
||||
{
|
||||
logD << "encoded: " << chunk->payloadSize << "\tsamples: " << encodedSamples << "\tres: " << res << "\n";
|
||||
encodedSamples = 0;
|
||||
chunk->payloadSize = encodedChunk->payloadSize;
|
||||
chunk->payload = (char*)realloc(chunk->payload, encodedChunk->payloadSize);
|
||||
memcpy(chunk->payload, encodedChunk->payload, encodedChunk->payloadSize);
|
||||
encodedChunk->payloadSize = 0;
|
||||
encodedChunk->payload = (char*)realloc(encodedChunk->payload, 0);
|
||||
}
|
||||
|
||||
return res;//chunk->duration<chronos::msec>().count();
|
||||
}
|
||||
|
||||
#define READSIZE 1024
|
||||
|
||||
static unsigned total_samples = 0; /* can use a 32-bit number due to WAVE size limitations */
|
||||
static FLAC__byte buffer[READSIZE/*samples*/ * 2/*bytes_per_sample*/ * 2/*channels*/]; /* we read the WAVE data into here */
|
||||
static FLAC__int32 pcm[READSIZE/*samples*/ * 2/*channels*/];
|
||||
|
||||
|
||||
|
||||
static void write_callback(const FLAC__StreamEncoder *encoder, const unsigned char*, long unsigned int bytes, unsigned int samples, unsigned int current_frame, void *client_data)
|
||||
FLAC__StreamEncoderWriteStatus write_callback(const FLAC__StreamEncoder *encoder,
|
||||
const FLAC__byte buffer[],
|
||||
size_t bytes,
|
||||
unsigned samples,
|
||||
unsigned current_frame,
|
||||
void *client_data)
|
||||
{
|
||||
cout << "write_callback: " << bytes << ", " << samples << ", " << current_frame << "\n";
|
||||
logD << "write_callback: " << bytes << ", " << samples << ", " << current_frame << "\n";
|
||||
FlacEncoder* flacEncoder = (FlacEncoder*)client_data;
|
||||
if ((current_frame == 0) && (bytes > 0) && (samples == 0))
|
||||
{
|
||||
msg::Header* headerChunk = flacEncoder->getHeaderChunk();
|
||||
headerChunk->payload = (char*)realloc(headerChunk->payload, headerChunk->payloadSize + bytes);
|
||||
memcpy(headerChunk->payload + headerChunk->payloadSize, buffer, bytes);
|
||||
headerChunk->payloadSize += bytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
encodedChunk->payload = (char*)realloc(encodedChunk->payload, encodedChunk->payloadSize + bytes);
|
||||
memcpy(encodedChunk->payload + encodedChunk->payloadSize, buffer, bytes);
|
||||
encodedChunk->payloadSize += bytes;
|
||||
encodedSamples += samples;
|
||||
}
|
||||
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -35,8 +82,9 @@ static void write_callback(const FLAC__StreamEncoder *encoder, const unsigned ch
|
|||
|
||||
void FlacEncoder::initEncoder()
|
||||
{
|
||||
encodedChunk = new msg::PcmChunk();
|
||||
headerChunk = new msg::Header("flac");
|
||||
FLAC__bool ok = true;
|
||||
FLAC__StreamEncoder *encoder = 0;
|
||||
FLAC__StreamEncoderInitStatus init_status;
|
||||
FLAC__StreamMetadata *metadata[2];
|
||||
FLAC__StreamMetadata_VorbisComment_Entry entry;
|
||||
|
@ -48,11 +96,10 @@ void FlacEncoder::initEncoder()
|
|||
}
|
||||
|
||||
ok &= FLAC__stream_encoder_set_verify(encoder, true);
|
||||
ok &= FLAC__stream_encoder_set_compression_level(encoder, 5);
|
||||
ok &= FLAC__stream_encoder_set_compression_level(encoder, 8);
|
||||
ok &= FLAC__stream_encoder_set_channels(encoder, sampleFormat.channels);
|
||||
ok &= FLAC__stream_encoder_set_bits_per_sample(encoder, sampleFormat.bits);
|
||||
ok &= FLAC__stream_encoder_set_sample_rate(encoder, sampleFormat.rate);
|
||||
ok &= FLAC__stream_encoder_set_total_samples_estimate(encoder, 0);
|
||||
|
||||
// now add some metadata; we'll add some tags and a padding block
|
||||
if(ok) {
|
||||
|
@ -76,7 +123,7 @@ void FlacEncoder::initEncoder()
|
|||
|
||||
// initialize encoder
|
||||
if(ok) {
|
||||
init_status = FLAC__stream_encoder_init_stream(encoder, write_callback, NULL, NULL, NULL, NULL);
|
||||
init_status = FLAC__stream_encoder_init_stream(encoder, write_callback, NULL, NULL, NULL, this);
|
||||
if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
|
||||
fprintf(stderr, "ERROR: initializing encoder: %s\n", FLAC__StreamEncoderInitStatusString[init_status]);
|
||||
ok = false;
|
||||
|
@ -122,12 +169,13 @@ void FlacEncoder::initEncoder()
|
|||
*/
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data)
|
||||
{
|
||||
(void)encoder, (void)client_data;
|
||||
fprintf(stderr, "wrote %d bytes, %d, %u samples, %u/%u frames\n", bytes_written, samples_written, total_samples, frames_written, total_frames_estimate);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -14,9 +14,11 @@ class FlacEncoder : public Encoder
|
|||
public:
|
||||
FlacEncoder(const msg::SampleFormat& format);
|
||||
virtual double encode(msg::PcmChunk* chunk);
|
||||
msg::Header* getHeaderChunk();
|
||||
|
||||
protected:
|
||||
void initEncoder();
|
||||
FLAC__StreamEncoder *encoder;
|
||||
// virtual void progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate);
|
||||
};
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "message/message.h"
|
||||
#include "pcmEncoder.h"
|
||||
#include "oggEncoder.h"
|
||||
#include "flacEncoder.h"
|
||||
#include "controlServer.h"
|
||||
|
||||
|
||||
|
@ -92,10 +93,7 @@ int main(int argc, char* argv[])
|
|||
else if (codec == "pcm")
|
||||
encoder.reset(new PcmEncoder(sampleFormat));
|
||||
else if (codec == "flac")
|
||||
{
|
||||
logO << "Not yet supported\n";
|
||||
return 1;
|
||||
}
|
||||
encoder.reset(new FlacEncoder(sampleFormat));
|
||||
else
|
||||
{
|
||||
logO << "unknown codec: " << codec << "\n";
|
||||
|
@ -144,8 +142,8 @@ int main(int argc, char* argv[])
|
|||
controlServer->send(chunk);
|
||||
//logD << chunk->tv_sec << ", " << chunk->tv_usec / 1000 << "\n";
|
||||
// addUs(tvChunk, 1000*chunk->getDuration());
|
||||
chronos::addUs(tvChunk, chunkDuration * 1000);
|
||||
nextTick += duration;
|
||||
chronos::addUs(tvChunk, chunkDuration * 1000);
|
||||
long currentTick = chronos::getTickCount();
|
||||
if (nextTick > currentTick)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue