mirror of
https://github.com/kunkundi/crossdesk.git
synced 2025-10-27 04:35:34 +08:00
Add opus codec test
This commit is contained in:
39
tests/opus/OpusDecoderImpl.cpp
Normal file
39
tests/opus/OpusDecoderImpl.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "OpusDecoderImpl.h"
|
||||
#define MAX_FRAME_SIZE 6 * 960
|
||||
#define CHANNELS 2
|
||||
|
||||
OpusDecoderImpl::OpusDecoderImpl(int sampleRate, int channel) {
|
||||
int err;
|
||||
decoder = opus_decoder_create(sampleRate, channel, &err);
|
||||
opus_decoder_ctl(decoder, OPUS_SET_LSB_DEPTH(16));
|
||||
sample_rate = sample_rate;
|
||||
channel_num = channel;
|
||||
if (err < 0 || decoder == NULL) {
|
||||
printf("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><EFBFBD>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pcm_file = fopen("decode.pcm", "wb+");
|
||||
}
|
||||
|
||||
bool OpusDecoderImpl::Decode(unsigned char* in_data, int len) {
|
||||
unsigned char pcm_bytes[MAX_FRAME_SIZE * CHANNELS * 2];
|
||||
opus_int16 out[MAX_FRAME_SIZE * CHANNELS];
|
||||
auto frame_size = opus_decode(decoder, in_data, len, out, MAX_FRAME_SIZE, 0);
|
||||
|
||||
if (frame_size < 0) {
|
||||
printf("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><EFBFBD>\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto i = 0; i < channel_num * frame_size; i++) {
|
||||
pcm_bytes[2 * i] = out[i] & 0xFF;
|
||||
pcm_bytes[2 * i + 1] = (out[i] >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
fwrite(pcm_bytes, sizeof(short), frame_size * channel_num, pcm_file);
|
||||
fflush(pcm_file);
|
||||
return true;
|
||||
}
|
||||
|
||||
OpusDecoderImpl::~OpusDecoderImpl() {}
|
||||
28
tests/opus/OpusDecoderImpl.h
Normal file
28
tests/opus/OpusDecoderImpl.h
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
#ifndef __OPUSDECODERIMPL_H
|
||||
#define __OPUSDECODERIMPL_H
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "base_type.h"
|
||||
#include "opus/opus.h"
|
||||
|
||||
class OpusDecoderImpl {
|
||||
private:
|
||||
/* data */
|
||||
OpusDecoder *decoder;
|
||||
int sample_rate;
|
||||
int channel_num;
|
||||
FILE *pcm_file;
|
||||
|
||||
public:
|
||||
bool Decode(unsigned char *in_data, int len);
|
||||
OpusDecoderImpl(int sampleRate, int channel);
|
||||
~OpusDecoderImpl();
|
||||
};
|
||||
|
||||
#endif
|
||||
116
tests/opus/OpusEncoderImpl.cpp
Normal file
116
tests/opus/OpusEncoderImpl.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
#include "OpusEncoderImpl.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "OpusDecoderImpl.h"
|
||||
#define MAX_PACKET_SIZE 3 * 1276
|
||||
|
||||
OpusEncoderImpl::OpusEncoderImpl(int sampleRate, int channel)
|
||||
: channel_num(channel), sample_rate(sampleRate) {
|
||||
int err;
|
||||
int applications[3] = {OPUS_APPLICATION_AUDIO, OPUS_APPLICATION_VOIP,
|
||||
OPUS_APPLICATION_RESTRICTED_LOWDELAY};
|
||||
|
||||
encoder = opus_encoder_create(sampleRate, channel_num, applications[1], &err);
|
||||
|
||||
if (err != OPUS_OK || encoder == NULL) {
|
||||
printf("<EFBFBD><EFBFBD><EFBFBD><EFBFBD>opus <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>\n");
|
||||
}
|
||||
|
||||
opus_encoder_ctl(encoder, OPUS_SET_VBR(0)); // 0:CBR, 1:VBR
|
||||
opus_encoder_ctl(encoder, OPUS_SET_VBR_CONSTRAINT(true));
|
||||
opus_encoder_ctl(encoder, OPUS_SET_BITRATE(96000));
|
||||
opus_encoder_ctl(encoder, OPUS_SET_COMPLEXITY(8)); // 8 0~10
|
||||
opus_encoder_ctl(encoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
|
||||
opus_encoder_ctl(encoder,
|
||||
OPUS_SET_LSB_DEPTH(16)); // ÿ<><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>16<31><36>bit<69><74>2<EFBFBD><32>byte
|
||||
opus_encoder_ctl(encoder, OPUS_SET_DTX(0));
|
||||
opus_encoder_ctl(encoder, OPUS_SET_INBAND_FEC(0));
|
||||
|
||||
EncodeRun();
|
||||
}
|
||||
|
||||
// every pcm frame takes 23ms
|
||||
void OpusEncoderImpl::Feed(unsigned char *data, int len) {
|
||||
mutex.lock();
|
||||
for (auto i = 0; i < len; i++) {
|
||||
pcm_queue.emplace(data[i]);
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
bool OpusEncoderImpl::PopFrame(StreamInfo &info) {
|
||||
if (info_queue.size() > 0) {
|
||||
access_mutex.lock();
|
||||
info = info_queue.front();
|
||||
info_queue.pop();
|
||||
access_mutex.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 48000 sample rate<74><65>48 samples/ms * 20ms * 2 channel = 1920
|
||||
void OpusEncoderImpl::EncodeRun() {
|
||||
m_thread = std::make_unique<std::thread>([this]() {
|
||||
const int frame_size = 48 * 20; // 960
|
||||
const int input_len = sizeof(opus_int16) * frame_size * 2;
|
||||
|
||||
OpusDecoderImpl decoder(48000, channel_num);
|
||||
|
||||
opus_int16 input_data[frame_size * 2] = {0};
|
||||
unsigned char input_buffer[input_len] = {0};
|
||||
unsigned char out_data[MAX_PACKET_SIZE] = {0};
|
||||
|
||||
while (isRuning) {
|
||||
if (pcm_queue.size() >= input_len) {
|
||||
mutex.lock();
|
||||
for (int i = 0; i < input_len; i++) {
|
||||
input_buffer[i] = pcm_queue.front();
|
||||
pcm_queue.pop();
|
||||
}
|
||||
|
||||
mutex.unlock();
|
||||
|
||||
auto ret = opus_encode(encoder, (opus_int16 *)input_buffer, frame_size,
|
||||
out_data, MAX_PACKET_SIZE);
|
||||
if (ret < 0) {
|
||||
printf("opus decode failed, %d\n", ret);
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned char *opus_buffer = (unsigned char *)malloc(ret);
|
||||
memcpy(opus_buffer, out_data, ret);
|
||||
decoder.Decode(opus_buffer, ret);
|
||||
|
||||
StreamInfo info;
|
||||
info.data = opus_buffer;
|
||||
info.len = ret;
|
||||
info.dts = 20;
|
||||
access_mutex.lock();
|
||||
info_queue.push(info);
|
||||
access_mutex.unlock();
|
||||
|
||||
} else {
|
||||
usleep(1000);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void OpusEncoderImpl::Stop() {
|
||||
isRuning = false;
|
||||
m_thread->join();
|
||||
|
||||
while (pcm_queue.size() > 0) {
|
||||
pcm_queue.pop();
|
||||
}
|
||||
|
||||
opus_encoder_destroy(encoder);
|
||||
}
|
||||
|
||||
OpusEncoderImpl::~OpusEncoderImpl() {}
|
||||
33
tests/opus/OpusEncoderImpl.h
Normal file
33
tests/opus/OpusEncoderImpl.h
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
#ifndef __OPUSENCODERIMPL_H
|
||||
#define __OPUSENCODERIMPL_H
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "base_type.h"
|
||||
#include "opus/opus.h"
|
||||
|
||||
class OpusEncoderImpl {
|
||||
private:
|
||||
OpusEncoder *encoder;
|
||||
const int channel_num;
|
||||
int sample_rate;
|
||||
std::queue<StreamInfo> info_queue;
|
||||
std::queue<unsigned char> pcm_queue;
|
||||
std::mutex mutex;
|
||||
bool isRuning = true;
|
||||
std::mutex access_mutex;
|
||||
std::unique_ptr<std::thread> m_thread;
|
||||
|
||||
public:
|
||||
OpusEncoderImpl(int sampleRate, int channel);
|
||||
void Feed(unsigned char *data, int len);
|
||||
bool PopFrame(StreamInfo &info);
|
||||
void EncodeRun();
|
||||
void Stop();
|
||||
~OpusEncoderImpl();
|
||||
};
|
||||
|
||||
#endif
|
||||
10
tests/opus/base_type.h
Normal file
10
tests/opus/base_type.h
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
#ifndef __BASE_TYPE_H__
|
||||
#define __BASE_TYPE_H__
|
||||
typedef struct StreamInfo {
|
||||
unsigned char *data;
|
||||
int len;
|
||||
int dts;
|
||||
} StreamInfo;
|
||||
|
||||
#endif
|
||||
31
tests/opus/main.cpp
Normal file
31
tests/opus/main.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "OpusEncoderImpl.h"
|
||||
#include "opus/opus.h"
|
||||
|
||||
int main() {
|
||||
OpusEncoderImpl* opusEncoder = new OpusEncoderImpl(48000, 2);
|
||||
|
||||
std::ifstream inputFile("ls.pcm", std::ios::binary);
|
||||
if (!inputFile) {
|
||||
std::cerr << "Failed to open input file." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char sample[960];
|
||||
while (inputFile.read(sample, 960)) {
|
||||
opusEncoder->Feed((unsigned char*)sample, 960);
|
||||
}
|
||||
|
||||
// // <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>opus<75><73>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD>̣߳<DFB3><CCA3><EFBFBD><EFBFBD><EFBFBD>ֻ<EFBFBD><D6BB>Ϊ<EFBFBD>˷<EFBFBD><CBB7><EFBFBD>
|
||||
// StreamInfo info;
|
||||
// while (opusEncoder.PopFrame(info)) {
|
||||
// .....
|
||||
// }
|
||||
|
||||
opusEncoder->Stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
96
tests/opus/opus_test.cpp
Normal file
96
tests/opus/opus_test.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
// Opus<75><73><EFBFBD>뺯<EFBFBD><EBBAAF>
|
||||
#include <opus/opus.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#define SAMPLE_RATE 48000
|
||||
#define CHANNELS 2
|
||||
#define FRAME_SIZE 960
|
||||
#define APPLICATION OPUS_APPLICATION_AUDIO
|
||||
|
||||
// <20><><EFBFBD>뺯<EFBFBD><EBBAAF>
|
||||
int encode(const std::vector<opus_int16>& pcm,
|
||||
std::vector<unsigned char>& opus) {
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
int error;
|
||||
OpusEncoder* encoder =
|
||||
opus_encoder_create(SAMPLE_RATE, CHANNELS, APPLICATION, &error);
|
||||
if (error != OPUS_OK) {
|
||||
std::cerr << "Failed to create encoder: " << opus_strerror(error)
|
||||
<< std::endl;
|
||||
return error;
|
||||
}
|
||||
|
||||
// <20><><EFBFBD>ñ<EFBFBD><C3B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
opus_encoder_ctl(encoder, OPUS_SET_BITRATE(64000));
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С
|
||||
int maxOpusSize = FRAME_SIZE * CHANNELS * sizeof(opus_int16);
|
||||
opus.resize(maxOpusSize);
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>
|
||||
int encodedSize =
|
||||
opus_encode(encoder, pcm.data(), FRAME_SIZE, opus.data(), maxOpusSize);
|
||||
if (encodedSize < 0) {
|
||||
std::cerr << "Encoding error: " << opus_strerror(encodedSize) << std::endl;
|
||||
return encodedSize;
|
||||
}
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ
|
||||
opus_encoder_destroy(encoder);
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD>С
|
||||
opus.resize(encodedSize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 3) {
|
||||
std::cerr << "Usage: " << argv[0] << " input.pcm output.opus" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>
|
||||
std::ifstream inputFile(argv[1], std::ios::binary);
|
||||
if (!inputFile) {
|
||||
std::cerr << "Failed to open input file." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// <20><>ȡPCM<43><4D><EFBFBD><EFBFBD>
|
||||
std::vector<opus_int16> pcmData;
|
||||
opus_int16 sample;
|
||||
while (inputFile.read(reinterpret_cast<char*>(&sample), sizeof(opus_int16))) {
|
||||
pcmData.push_back(sample);
|
||||
}
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>ΪOpus<75><73>ʽ
|
||||
std::vector<unsigned char> opusData;
|
||||
int result = encode(pcmData, opusData);
|
||||
if (result != 0) {
|
||||
std::cerr << "Encoding failed with error code " << result << std::endl;
|
||||
return result;
|
||||
}
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>
|
||||
std::ofstream outputFile(argv[2], std::ios::binary);
|
||||
if (!outputFile) {
|
||||
std::cerr << "Failed to open output file." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// д<><D0B4>Opus<75><73><EFBFBD><EFBFBD>
|
||||
outputFile.write(reinterpret_cast<const char*>(opusData.data()),
|
||||
opusData.size());
|
||||
|
||||
// <20><><EFBFBD><EFBFBD>
|
||||
std::cout << "Encoding complete. size:" << pcmData.size() * 2 << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user