C++ Library Manager for Windows, Linux, and MacOS
Argument Parser for Modern C++
#include "argparse/argparse.hpp"
int main(int argc, const char** argv) {
argparse::ArgumentParser parser;
parser.add_argument("input_file").help("Input file path");
parser.add_argument("-o", "--output").default_value("output.txt").help("Output file path");
auto args = parser.parse_args(argc, argv);
std::string input_file = args.get<std::string>("input_file");
std::string output_file = args.get<std::string>("output");
// Your code to process input and output files
// ...
return 0;
}A modern formatting library
#include <fmt/format.h>
int main() {
std::string name = "John";
int age = 30;
std::string formatted = fmt::format("Name: {}, Age: {}", name, age);
fmt::print("{}\n", formatted);
return 0;
}Fast C++ logging library
#include <spdlog/spdlog.h>
int main() {
// Create a logger
auto logger = spdlog::stdout_logger_mt("console");
// Log messages
logger->info("This is an info message.");
logger->error("This is an error message.");
return 0;
}C++ Requests: Curl for People, a spiritual port of Python Requests
#include <cpr/cpr.h>
int main() {
cpr::Response response = cpr::Get(cpr::Url{"https://example.com"});
if (response.status_code == 200) {
std::cout << response.text << std::endl;
} else {
std::cerr << "Request failed with status code: " << response.status_code << std::endl;
}
return 0;
}JSON for Modern C++
#include <nlohmann/json.hpp>
int main() {
nlohmann::json data = {
{"name", "John"},
{"age", 30}
};
std::string json_str = data.dump();
// Parse JSON
auto parsed_data = nlohmann::json::parse(json_str);
std::cout << "Name: " << parsed_data["name"] << ", Age: " << parsed_data["age"] << std::endl;
return 0;
}Simple, secure & standards-compliant web server for demanding applications
#include <uWS/uWS.h>
int main() {
uWS::Hub hub;
hub.onMessage([](uWS::WebSocket<uWS::SERVER> *ws, char *message, size_t length, uWS::OpCode opCode) {
std::string msg(message, length);
ws->send(msg, opCode);
});
if (hub.listen(3000)) {
std::cout << "Server listening on port 3000" << std::endl;
hub.run();
}
return 0;
}Protocol Buffers - Google's data interchange format Example code for Protocol Buffers can be found in the official documentation: Protocol Buffers - C++ Tutorial
Certainly! Protocol Buffers (protobuf) is a popular serialization format developed by Google. Below are examples of how to serialize and deserialize data using protobuf in C++.
First, you need to define your data structure in a .proto file. For example, let's create a simple message for a person's information:
// person.proto
syntax = "proto3";
message Person {
string name = 1;
int32 age = 2;
}You'll need to use the Protocol Buffers compiler (protoc) to compile your .proto file into C++ code. Run the following command to generate the C++ files:
protoc --cpp_out=. person.protoThis command will generate person.pb.h and person.pb.cc.
Now, you can use the generated C++ classes to create and serialize a Person message:
#include "person.pb.h"
#include <iostream>
#include <fstream>
int main() {
// Create a Person message
Person person;
person.set_name("John");
person.set_age(30);
// Serialize the Person message to a binary format
std::string serializedData;
person.SerializeToString(&serializedData);
// Save the serialized data to a file
std::ofstream output("person.dat", std::ios::binary);
output.write(serializedData.c_str(), serializedData.size());
output.close();
std::cout << "Serialized data saved to 'person.dat'" << std::endl;
return 0;
}To deserialize the data, you can read the binary data from the file and parse it:
#include "person.pb.h"
#include <iostream>
#include <fstream>
int main() {
// Read the serialized data from a file
std::ifstream input("person.dat", std::ios::binary);
std::string serializedData((std::istreambuf_iterator<char>(input)), (std::istreambuf_iterator<char>()));
input.close();
// Parse the serialized data into a Person message
Person person;
if (!person.ParseFromString(serializedData)) {
std::cerr << "Failed to parse serialized data." << std::endl;
return 1;
}
// Access the deserialized data
std::cout << "Name: " << person.name() << ", Age: " << person.age() << std::endl;
return 0;
}Compile and run the serialization and deserialization code. Make sure you have the person.dat file in the same directory, which was created in the serialization step. This code will read the serialized data, parse it back into a Person message, and print the person's name and age.
Remember to include error handling in your code to handle cases where deserialization may fail due to data corruption or other issues.
The C-based gRPC (C++, Python, Ruby, Objective-C, PHP, C#) Example code for gRPC can be found in the official documentation: gRPC C++ Quick Start
以下是一个使用 gRPC C++ 的一元请求示例,其中客户端调用一个名为 "Hello" 的服务,服务器返回 "World"。
首先,您需要创建一个 .proto 文件来定义服务和消息类型。在这个示例中,我们将创建一个名为 HelloService 的服务,其中包含一个名为 SayHello 的方法:
syntax = "proto3";
service HelloService {
rpc SayHello(HelloRequest) returns (HelloResponse);
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string message = 1;
}接下来,使用 Protocol Buffers 编译器生成 C++ 代码:
protoc --grpc_out=. --cpp_out=. your_proto_file.proto
然后,您可以编写客户端和服务器的代码。
#include <iostream>
#include <grpcpp/grpcpp.h>
#include "your_proto_file.grpc.pb.h"
class HelloServiceImpl final : public HelloService::Service {
public:
grpc::Status SayHello(grpc::ServerContext* context, const HelloRequest* request, HelloResponse* response) override {
std::string name = request->name();
response->set_message("Hello, " + name + "!");
return grpc::Status::OK;
}
};
int main() {
std::string server_address("0.0.0.0:50051");
HelloServiceImpl service;
grpc::ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
std::cout << "Server listening on " << server_address << std::endl;
server->Wait();
return 0;
} #include <iostream>
#include <grpcpp/grpcpp.h>
#include "your_proto_file.grpc.pb.h"
int main() {
std::string server_address("localhost:50051");
grpc::ChannelArguments channel_args;
channel_args.SetMaxReceiveMessageSize(INT_MAX);
channel_args.SetMaxSendMessageSize(INT_MAX);
grpc::Channel channel = grpc::CreateCustomChannel(server_address, grpc::InsecureChannelCredentials(), channel_args);
std::unique_ptr<HelloService::Stub> stub = HelloService::NewStub(channel);
HelloRequest request;
request.set_name("World");
HelloResponse response;
grpc::ClientContext context;
grpc::Status status = stub->SayHello(&context, request, &response);
if (status.ok()) {
std::cout << "Server says: " << response.message() << std::endl;
} else {
std::cerr << "RPC failed: " << status.error_message() << std::endl;
}
return 0;
}请确保将 your\_proto\_file.proto 替换为您自己的 .proto 文件名称,然后使用上述步骤编译和运行服务器和客户端代码。这个示例中的服务器接收客户端的名字,并返回包含 "Hello, " 加上名字的消息。
以下是一个使用 gRPC C++ 的客户端流示例,客户端不停地发送当前日期时间给服务器。
首先,您需要创建一个 .proto 文件来定义服务和消息类型。在这个示例中,我们将创建一个名为 DateTimeService 的服务,其中包含一个名为 StreamDateTime 的方法:
syntax = "proto3";
service DateTimeService {
rpc StreamDateTime(stream DateTimeRequest) returns (DateTimeResponse);
}
message DateTimeRequest {
// 空消息,用于客户端发送时间请求
}
message DateTimeResponse {
string datetime = 1;
}接下来,使用 Protocol Buffers 编译器生成 C++ 代码:
protoc --grpc_out=. --cpp_out=. your_proto_file.proto
然后,您可以编写客户端和服务器的代码。
#include <iostream>
#include <grpcpp/grpcpp.h>
#include <chrono>
#include <thread>
#include "your_proto_file.grpc.pb.h"
class DateTimeServiceImpl final : public DateTimeService::Service {
public:
grpc::Status StreamDateTime(grpc::ServerContext* context, grpc::ServerReaderWriter<DateTimeResponse, DateTimeRequest>* stream) override {
while (true) {
DateTimeResponse response;
std::time_t now = std::time(nullptr);
response.set_datetime(std::ctime(&now));
grpc::WriteOptions options;
if (!stream->Write(response, options)) {
break;
}
// 暂停一秒钟再发送下一个时间
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return grpc::Status::OK;
}
};
int main() {
std::string server_address("0.0.0.0:50051");
DateTimeServiceImpl service;
grpc::ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
std::cout << "Server listening on " << server_address << std::endl;
server->Wait();
return 0;
} #include <iostream>
#include <grpcpp/grpcpp.h>
#include "your_proto_file.grpc.pb.h"
int main() {
std::string server_address("localhost:50051");
grpc::ChannelArguments channel_args;
channel_args.SetMaxReceiveMessageSize(INT_MAX);
channel_args.SetMaxSendMessageSize(INT_MAX);
grpc::Channel channel = grpc::CreateCustomChannel(server_address, grpc::InsecureChannelCredentials(), channel_args);
std::unique_ptr<DateTimeService::Stub> stub = DateTimeService::NewStub(channel);
grpc::ClientContext context;
std::shared_ptr<grpc::ClientReader<DateTimeResponse>> reader = stub->StreamDateTime(&context, grpc::ClientContext::CompletionQueue());
DateTimeResponse response;
while (reader->Read(&response)) {
std::cout << "Server says: " << response.datetime() << std::endl;
}
grpc::Status status = reader->Finish();
if (status.ok()) {
std::cout << "Server stream finished successfully." << std::endl;
} else {
std::cerr << "RPC failed: " << status.error_message() << std::endl;
}
return 0;
}请确保将 your\_proto\_file.proto 替换为您自己的 .proto 文件名称,然后使用上述步骤编译和运行服务器和客户端代码。在此示例中,服务器会不断地向客户端发送当前日期时间,客户端会接收并打印这些时间信息。客户端和服务器之间使用流来实现数据的持续传输。
以下是一个使用 gRPC C++ 的服务端流示例,服务器不停地向客户端发送当前日期时间。
首先,您需要创建一个 .proto 文件来定义服务和消息类型。在这个示例中,我们将创建一个名为 DateTimeService 的服务,其中包含一个名为 StreamDateTime 的方法:
syntax = "proto3";
service DateTimeService {
rpc StreamDateTime(DateTimeRequest) returns (stream DateTimeResponse);
}
message DateTimeRequest {
// 空消息,用于客户端发送请求
}
message DateTimeResponse {
string datetime = 1;
}接下来,使用 Protocol Buffers 编译器生成 C++ 代码:
protoc --grpc_out=. --cpp_out=. your_proto_file.proto
然后,您可以编写客户端和服务器的代码。
#include <iostream>
#include <grpcpp/grpcpp.h>
#include <chrono>
#include <thread>
#include "your_proto_file.grpc.pb.h"
class DateTimeServiceImpl final : public DateTimeService::Service {
public:
grpc::Status StreamDateTime(grpc::ServerContext* context, const DateTimeRequest* request, grpc::ServerWriter<DateTimeResponse>* writer) override {
while (true) {
DateTimeResponse response;
std::time_t now = std::time(nullptr);
response.set_datetime(std::ctime(&now));
grpc::WriteOptions options;
if (!writer->Write(response, options)) {
break;
}
// 暂停一秒钟再发送下一个时间
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return grpc::Status::OK;
}
};
int main() {
std::string server_address("0.0.0.0:50051");
DateTimeServiceImpl service;
grpc::ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
std::cout << "Server listening on " << server_address << std::endl;
server->Wait();
return 0;
} #include <iostream>
#include <grpcpp/grpcpp.h>
#include "your_proto_file.grpc.pb.h"
int main() {
std::string server_address("localhost:50051");
grpc::ChannelArguments channel_args;
channel_args.SetMaxReceiveMessageSize(INT_MAX);
channel_args.SetMaxSendMessageSize(INT_MAX);
grpc::Channel channel = grpc::CreateCustomChannel(server_address, grpc::InsecureChannelCredentials(), channel_args);
std::unique_ptr<DateTimeService::Stub> stub = DateTimeService::NewStub(channel);
DateTimeRequest request;
std::shared_ptr<grpc::ClientReader<DateTimeResponse>> reader = stub->StreamDateTime(&request, grpc::ClientContext::CompletionQueue());
DateTimeResponse response;
while (reader->Read(&response)) {
std::cout << "Server says: " << response.datetime() << std::endl;
}
grpc::Status status = reader->Finish();
if (status.ok()) {
std::cout << "Server stream finished successfully." << std::endl;
} else {
std::cerr << "RPC failed: " << status.error_message() << std::endl;
}
return 0;
}请确保将 your\_proto\_file.proto 替换为您自己的 .proto 文件名称,然后使用上述步骤编译和运行服务器和客户端代码。在此示例中,服务器会不断地向客户端发送当前日期时间,客户端会接收并打印这些时间信息。服务器和客户端之间使用流来实现数据的持续传输,这是服务端流 gRPC 的工作方式。
以下是一个使用 gRPC C++ 的双向流示例,双方不停地交换自身的计算机名称和当前日期时间。
首先,您需要创建一个 .proto 文件来定义服务和消息类型。在这个示例中,我们将创建一个名为 ComputerInfoService 的服务,其中包含一个名为 ExchangeInfo 的方法:
syntax = "proto3";
service ComputerInfoService {
rpc ExchangeInfo(stream ComputerInfoRequest) returns (stream ComputerInfoResponse);
}
message ComputerInfoRequest {
string computer_name = 1;
}
message ComputerInfoResponse {
string computer_name = 1;
string datetime = 2;
}接下来,使用 Protocol Buffers 编译器生成 C++ 代码:
protoc --grpc_out=. --cpp_out=. your_proto_file.proto
然后,您可以编写客户端和服务器的代码。
#include <iostream>
#include <grpcpp/grpcpp.h>
#include <chrono>
#include <thread>
#include <sstream>
#include "your_proto_file.grpc.pb.h"
class ComputerInfoServiceImpl final : public ComputerInfoService::Service {
public:
grpc::Status ExchangeInfo(grpc::ServerContext* context, grpc::ServerReaderWriter<ComputerInfoResponse, ComputerInfoRequest>* stream) override {
while (true) {
ComputerInfoRequest request;
if (!stream->Read(&request)) {
break;
}
std::string computer_name = request.computer_name();
ComputerInfoResponse response;
response.set_computer_name(computer_name);
std::time_t now = std::time(nullptr);
response.set_datetime(std::ctime(&now));
grpc::WriteOptions options;
if (!stream->Write(response, options)) {
break;
}
// 暂停一秒钟再发送下一个信息
std::this_thread::sleep_for(std::chrono::seconds(1));
}
return grpc::Status::OK;
}
};
int main() {
std::string server_address("0.0.0.0:50051");
ComputerInfoServiceImpl service;
grpc::ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
std::cout << "Server listening on " << server_address << std::endl;
server->Wait();
return 0;
} #include <iostream>
#include <grpcpp/grpcpp.h>
#include <thread>
#include "your_proto_file.grpc.pb.h"
class ComputerInfoClient {
public:
ComputerInfoClient(std::shared_ptr<grpc::Channel> channel)
: stub_(ComputerInfoService::NewStub(channel)) {}
void ExchangeInfo() {
grpc::ClientContext context;
std::shared_ptr<grpc::ClientReaderWriter<ComputerInfoResponse, ComputerInfoRequest>> stream = stub_->ExchangeInfo(&context);
std::string computer_name = "Client";
while (true) {
ComputerInfoRequest request;
request.set_computer_name(computer_name);
grpc::WriteOptions options;
if (!stream->Write(request, options)) {
break;
}
ComputerInfoResponse response;
if (!stream->Read(&response)) {
break;
}
std::cout << "Server says: " << response.computer_name() << " - " << response.datetime() << std::endl;
// 暂停一秒钟再发送下一个信息
std::this_thread::sleep_for(std::chrono::seconds(1));
}
stream->WritesDone();
grpc::Status status = stream->Finish();
if (status.ok()) {
std::cout << "Server stream finished successfully." << std::endl;
} else {
std::cerr << "RPC failed: " << status.error_message() << std::endl;
}
}
private:
std::unique_ptr<ComputerInfoService::Stub> stub_;
};
int main() {
std::string server_address("localhost:50051");
grpc::ChannelArguments channel_args;
channel_args.SetMaxReceiveMessageSize(INT_MAX);
channel_args.SetMaxSendMessageSize(INT_MAX);
grpc::Channel channel = grpc::CreateCustomChannel(server_address, grpc::InsecureChannelCredentials(), channel_args);
ComputerInfoClient client(channel);
client.ExchangeInfo();
return 0;
}A complete, cross-platform solution for audio and video You can find FFmpeg usage examples in its documentation: FFmpeg Documentation
GitHub Repo Build FFmpeg for Windows
编码H.265
#include <iostream>
#include <string>
#include <stdexcept>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
}
int main() {
// Initialize FFmpeg libraries
av_register_all();
avcodec_register_all();
// Input settings
std::string inputFileName = "input.mp4"; // Replace with your input video file name
std::string outputFileName = "output.h265"; // Output file in H.265 format
// Open the input file
AVFormatContext* formatContext = nullptr;
if (avformat_open_input(&formatContext, inputFileName.c_str(), nullptr, nullptr) != 0) {
std::cerr << "Error opening input file." << std::endl;
return 1;
}
if (avformat_find_stream_info(formatContext, nullptr) < 0) {
std::cerr << "Error finding stream information." << std::endl;
avformat_close_input(&formatContext);
return 1;
}
// Find the video stream
int videoStreamIndex = -1;
for (unsigned int i = 0; i < formatContext->nb_streams; i++) {
if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStreamIndex = i;
break;
}
}
if (videoStreamIndex == -1) {
std::cerr << "Error: No video stream found." << std::endl;
avformat_close_input(&formatContext);
return 1;
}
// Find the codec for H.265/HEVC
AVCodec* codec = avcodec_find_encoder_by_name("libx265");
if (!codec) {
std::cerr << "Error: libx265 not found." << std::endl;
avformat_close_input(&formatContext);
return 1;
}
// Create a codec context and set parameters
AVCodecContext* codecContext = avcodec_alloc_context3(codec);
if (!codecContext) {
std::cerr << "Error allocating codec context." << std::endl;
avformat_close_input(&formatContext);
return 1;
}
codecContext->width = formatContext->streams[videoStreamIndex]->codecpar->width;
codecContext->height = formatContext->streams[videoStreamIndex]->codecpar->height;
codecContext->bit_rate = 2000000; // Adjust the bit rate as needed
codecContext->time_base = {1, 25}; // Adjust the frame rate as needed
// Set H.265 specific options
av_opt_set(codecContext->priv_data, "preset", "medium", 0); // Encoding preset (e.g., medium, slow, fast)
av_opt_set(codecContext->priv_data, "x265-params", "keyint=30:min-keyint=30:scenecut=0", 0); // x265 parameters
// Open the codec
if (avcodec_open2(codecContext, codec, nullptr) < 0) {
std::cerr << "Error opening codec." << std::endl;
avcodec_free_context(&codecContext);
avformat_close_input(&formatContext);
return 1;
}
// Open the output file
AVFormatContext* outputFormatContext = nullptr;
if (avformat_alloc_output_context2(&outputFormatContext, nullptr, nullptr, outputFileName.c_str()) < 0) {
std::cerr << "Error creating output format context." << std::endl;
avcodec_free_context(&codecContext);
avformat_close_input(&formatContext);
return 1;
}
if (avio_open(&outputFormatContext->pb, outputFileName.c_str(), AVIO_FLAG_WRITE) < 0) {
std::cerr << "Error opening output file." << std::endl;
avcodec_free_context(&codecContext);
avformat_free_context(outputFormatContext);
avformat_close_input(&formatContext);
return 1;
}
AVStream* outputVideoStream = avformat_new_stream(outputFormatContext, codec);
if (!outputVideoStream) {
std::cerr << "Error creating output video stream." << std::endl;
avcodec_free_context(&codecContext);
avformat_free_context(outputFormatContext);
avformat_close_input(&formatContext);
return 1;
}
// Copy the codec parameters from the input stream to the output stream
avcodec_parameters_copy(outputVideoStream->codecpar, formatContext->streams[videoStreamIndex]->codecpar);
outputVideoStream->codecpar->codec_id = AV_CODEC_ID_HEVC; // Set codec to H.265/HEVC
// Write the output format header
if (avformat_write_header(outputFormatContext, nullptr) < 0) {
std::cerr << "Error writing output format header." << std::endl;
avcodec_free_context(&codecContext);
avformat_free_context(outputFormatContext);
avformat_close_input(&formatContext);
return 1;
}
// Encode and write frames
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = nullptr;
pkt.size = 0;
AVFrame* frame = av_frame_alloc();
if (!frame) {
std::cerr << "Error allocating frame." << std::endl;
avcodec_free_context(&codecContext);
avformat_free_context(outputFormatContext);
avformat_close_input(&formatContext);
return 1;
}
int frameNumber = 0;
int gotOutput = 0;
while (av_read_frame(formatContext, &pkt) >= 0) {
if (pkt.stream_index == videoStreamIndex) {
// Send the frame for encoding
avcodec_encode_video2(codecContext, &pkt, frame, &gotOutput);
if (gotOutput) {
// Write the encoded frame to the output file
av_packet_rescale_ts(&pkt, codecContext->time_base, outputVideoStream->time_base);
pkt.stream_index = outputVideoStream->index;
av_write_frame(outputFormatContext, &pkt);
}
}
av_packet_unref(&pkt);
frameNumber++;
}
// Flush the encoder
avcodec_encode_video2(codecContext, &pkt, nullptr, &gotOutput);
if (gotOutput) {
av_packet_rescale_ts(&pkt, codecContext->time_base, outputVideoStream->time_base);
pkt.stream_index = outputVideoStream->index;
av_write_frame(outputFormatContext, &pkt);
}
// Write the trailer
av_write_trailer(outputFormatContext);
// Clean up
avcodec_free_context(&codecContext);
avformat_free_context(outputFormatContext);
avformat_close_input(&formatContext);
av_frame_free(&frame);
return 0;
}解码H.265
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
}
int main() {
// Initialize FFmpeg libraries
av_register_all();
avcodec_register_all();
// Open the input file
const char* inputFileName = "input.h265";
AVFormatContext* formatContext = avformat_alloc_context();
if (avformat_open_input(&formatContext, inputFileName, NULL, NULL) != 0) {
std::cerr << "Error opening the input file." << std::endl;
return -1;
}
// Find the video stream information
if (avformat_find_stream_info(formatContext, NULL) < 0) {
std::cerr << "Could not find stream information." << std::endl;
return -1;
}
// Find the video stream
AVCodec* codec = NULL;
int videoStreamIndex = -1;
for (int i = 0; i < formatContext->nb_streams; i++) {
if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStreamIndex = i;
codec = avcodec_find_decoder(formatContext->streams[i]->codecpar->codec_id);
if (codec == NULL) {
std::cerr << "Unsupported codec." << std::endl;
return -1;
}
break;
}
}
// Create a codec context
AVCodecContext* codecContext = avcodec_alloc_context3(codec);
if (avcodec_parameters_to_context(codecContext, formatContext->streams[videoStreamIndex]->codecpar) < 0) {
std::cerr << "Failed to copy codec parameters to codec context." << std::endl;
return -1;
}
// Open the codec
if (avcodec_open2(codecContext, codec, NULL) < 0) {
std::cerr << "Could not open codec." << std::endl;
return -1;
}
// Initialize the packet and frame
AVPacket packet;
av_init_packet(&packet);
AVFrame* frame = av_frame_alloc();
// Decode frames
int frameCount = 0;
while (av_read_frame(formatContext, &packet) >= 0) {
if (packet.stream_index == videoStreamIndex) {
if (avcodec_send_packet(codecContext, &packet) == 0) {
while (avcodec_receive_frame(codecContext, frame) == 0) {
// You can save or process the decoded frame here
// For example, save the frame as an image
char filename[50];
snprintf(filename, sizeof(filename), "frame%d.jpg", frameCount);
av_write_image_frame(filename, frame);
frameCount++;
}
}
}
av_packet_unref(&packet);
}
// Clean up
avcodec_free_context(&codecContext);
av_frame_free(&frame);
avformat_close_input(&formatContext);
avformat_free_context(formatContext);
return 0;
}
Open-source multimedia framework You can find tutorials and documentation on the official GStreamer website: GStreamer Documentation
H.265基本码流转换成传输流
#include <gst/gst.h>
int main(int argc, char *argv[]) {
// Initialize GStreamer
gst_init(&argc, &argv);
// Input H.265 encoded file
const gchar* input_file = "input.h265";
// Output H.265 transport stream file
const gchar* output_file = "output.ts";
// Create a GStreamer pipeline
GstElement *pipeline, *filesrc, *h265parse, *mux, *filesink;
GstBus *bus;
GstMessage *msg;
GstStateChangeReturn ret;
pipeline = gst_pipeline_new("h265-to-ts");
filesrc = gst_element_factory_make("filesrc", "file-source");
h265parse = gst_element_factory_make("h265parse", "h265-parser");
mux = gst_element_factory_make("mpegtsmux", "mpegts-mux");
filesink = gst_element_factory_make("filesink", "file-sink");
if (!pipeline || !filesrc || !h265parse || !mux || !filesink) {
g_printerr("Not all elements could be created.\n");
return -1;
}
// Set input and output file locations
g_object_set(G_OBJECT(filesrc), "location", input_file, NULL);
g_object_set(G_OBJECT(filesink), "location", output_file, NULL);
// Add elements to the pipeline
gst_bin_add_many(GST_BIN(pipeline), filesrc, h265parse, mux, filesink, NULL);
// Link elements together
if (!gst_element_link(filesrc, h265parse) ||
!gst_element_link(h265parse, mux) ||
!gst_element_link(mux, filesink)) {
g_printerr("Elements could not be linked.\n");
gst_object_unref(pipeline);
return -1;
}
// Set the pipeline to the playing state
ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE) {
g_printerr("Unable to set the pipeline to the playing state.\n");
gst_object_unref(pipeline);
return -1;
}
// Wait until the conversion is complete
bus = gst_element_get_bus(pipeline);
msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE,
GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
// Stop and cleanup
gst_message_unref(msg);
gst_object_unref(bus);
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);
g_print("File %s converted to %s\n", input_file, output_file);
return 0;
}Command-line video player (library) Usage examples and documentation can be found on the mpv website: mpv Documentation
GitHub Repo Build mpv for Windows
播放自定义流
#include <iostream>
#include <mpv/client.h>
#include <mpv/stream_cb.h>
// 自定义数据读取回调函数
ssize_t custom_read_fn(void *user_data, void *buffer, size_t size) {
// 在这里实现您的自定义数据读取逻辑
// 将数据写入buffer,并返回实际读取的字节数
// 如果没有更多数据可用,可以返回0表示结束
// 如果发生错误,返回-1
// 示例:假设您有一个自定义数据源,每次读取100字节
static const char custom_data[] = "Your custom data source content";
static size_t offset = 0;
if (offset >= sizeof(custom_data))
return 0;
size_t bytes_to_copy = std::min(size, sizeof(custom_data) - offset);
memcpy(buffer, custom_data + offset, bytes_to_copy);
offset += bytes_to_copy;
return bytes_to_copy;
}
int main() {
mpv_handle *mpv;
// 初始化mpv实例
mpv = mpv_create();
if (!mpv) {
std::cerr << "Failed to create mpv instance." << std::endl;
return 1;
}
// 设置mpv选项,可以根据需要进行调整
mpv_set_option_string(mpv, "input-default-bindings", "yes");
mpv_set_option_string(mpv, "input-vo-keyboard", "yes");
mpv_set_option_string(mpv, "input-ipc-server", "/tmp/mpvsocket");
// 打开一个X11窗口,如果需要的话
mpv_set_option_string(mpv, "wid", "X11 Window ID");
// 设置自定义数据读取回调函数
mpv_stream_cb_info stream_cb_info;
memset(&stream_cb_info, 0, sizeof(stream_cb_info));
stream_cb_info.read_cb = custom_read_fn;
// 关联自定义数据读取回调函数与mpv实例
if (mpv_stream_cb_create(mpv, &stream_cb_info) < 0) {
std::cerr << "Failed to create stream callback." << std::endl;
mpv_terminate_destroy(mpv);
return 1;
}
// 使用mpv命令播放流
const char *cmd[] = {
"loadfile", "stream://", NULL
};
if (mpv_command(mpv, cmd) < 0) {
std::cerr << "Failed to load stream." << std::endl;
mpv_terminate_destroy(mpv);
return 1;
}
// 等待播放结束
mpv_event *event;
while (1) {
event = mpv_wait_event(mpv, -1);
if (event->event_id == MPV_EVENT_END_FILE)
break;
}
// 清理和销毁mpv实例
mpv_terminate_destroy(mpv);
return 0;
}BS::thread_pool: a fast, lightweight C++17 thread pool library
#include <bshoshany/thread_pool.h>
int main() {
bshoshany::thread_pool pool(4); // Create a thread pool with 4 worker threads
// Submit tasks to the thread pool
for (int i = 0; i < 10; ++i) {
pool.submit([i] {
std::cout << "Task " << i << " executed by thread " << std::this_thread::get_id() << std::endl;
});
}
// Shutdown the thread pool when done
pool.shutdown();
return 0;
}NVIDIA 2D Image and Signal Processing Performance Primitives (NPP) Documentation for NVIDIA NPP can be found on the NVIDIA website: NVIDIA NPP Documentation
pixel_fmt_cuda转换成rgb24
#include <iostream>
#include <npp.h>
int main() {
// 初始化NPP库
NppStatus nppStatus = nppiInit();
if (nppStatus != NPP_SUCCESS) {
std::cerr << "NPP initialization failed: " << nppGetErrorString(nppStatus) << std::endl;
return 1;
}
// 定义输入NV12图像和输出RGB24图像的尺寸
int width = 1920; // 替换为您的图像宽度
int height = 1080; // 替换为您的图像高度
// 分配和初始化NV12和RGB24图像缓冲区
Npp8u* pSrcNV12 = static_cast<Npp8u*>(malloc(width * height * 3 / 2)); // NV12格式
Npp8u* pDstRGB24 = static_cast<Npp8u*>(malloc(width * height * 3)); // RGB24格式
// 在这里填充pSrcNV12缓冲区,将NV12图像数据加载到内存中
// 创建NPP图像描述符
NppiSize oSize = { width, height };
NppiRect oROI = { 0, 0, width, height };
NppiSize oSrcStep = { width, width / 2 }; // NV12格式的步长
NppiSize oDstStep = { width * 3, width * 3 }; // RGB24格式的步长
// 使用NPP库函数执行NV12到RGB24的转换
nppStatus = nppiYCbCr420ToBGR_8u_P2C3R(pSrcNV12, oSrcStep, pDstRGB24, oDstStep, oSize, oROI);
if (nppStatus != NPP_SUCCESS) {
std::cerr << "NPP conversion failed: " << nppGetErrorString(nppStatus) << std::endl;
free(pSrcNV12);
free(pDstRGB24);
return 1;
}
// 现在pDstRGB24缓冲区包含RGB24格式的图像数据,可以进行后续处理或显示
// 释放内存
free(pSrcNV12);
free(pDstRGB24);
// 关闭NPP库
nppStatus = nppiFree();
if (nppStatus != NPP_SUCCESS) {
std::cerr << "NPP cleanup failed: " << nppGetErrorString(nppStatus) << std::endl;
return 1;
}
return 0;
}GPU-accelerated JPEG decoder, encoder, and transcoder Documentation for NVIDIA nvJPEG can be found on the NVIDIA website: NVIDIA nvJPEG Documentation
jpeg编码
#include <iostream>
#include <npp.h>
#include <nvjpeg.h>
int main() {
// 1. 使用NPP将图像转换为YUV 420P
// 假设输入数据为RGB24
int width = 1920;
int height = 1080;
Npp8u *pSrcRGB = nullptr; // 这是您的原始数据
Npp8u *pDstYUV = nullptr; // 这是转换后的YUV数据
// 分配内存和其他初始化...
// 使用NPP将RGB转换为YUV420
// 对于这一部分,您可能需要使用一系列的npp函数调用
// 注意:以下是一个伪代码调用,并不是一个真实的函数
// nppConvertRGBToYUV420(pSrcRGB, pDstYUV, width, height);
// 2. 使用nvJPEG编码YUV 420P为JPEG
nvjpegHandle_t nvjpegHandle;
nvjpegEncoderState_t encoderState;
nvjpegEncoderParams_t encoderParams;
nvjpegStatus_t nvjpegStatus = nvjpegCreateSimple(&nvjpegHandle);
// 初始化 nvJPEG 结构和分配内存...
nvjpegJpegState_t jpegState;
nvjpegCreateJpegState(nvjpegHandle, &jpegState);
nvjpegEncoderParamsCreate(nvjpegHandle, &encoderParams, NVJPEG_BACKEND_DEFAULT);
// 使用默认参数编码
nvjpegEncoderParamsSetDefaults(nvjpegHandle, encoderParams);
// 设置图像格式
nvjpegInputFormat_t inputFormat = NVJPEG_INPUT_YUV420;
nvjpegEncodeSetInputFormat(encoderParams, inputFormat);
// 执行编码
size_t jpegSize;
nvjpegEncodeImage(nvjpegHandle, encoderState, encoderParams, &jpegState, pDstYUV, &jpegSize);
// pDstYUV 现在应该包含编码的 JPEG 数据
// 清理工作:释放内存、销毁NPP和nvJPEG资源...
return 0;
}Abseil Common Libraries (C++) Documentation for Abseil can be found on the Abseil website: Abseil Documentation
计算文件sha1摘要
#include <iostream>
#include <fstream>
#include <string>
#include <absl/strings/string_view.h>
#include <absl/crypto/sha.h>
int main() {
// 打开文件
std::ifstream file("your_file.txt", std::ios::binary);
if (!file.is_open()) {
std::cerr << "Failed to open file." << std::endl;
return 1;
}
// 创建SHA-1计算器
absl::crypto::Sha1 sha1;
// 缓冲区大小(根据需要进行调整)
constexpr size_t buffer_size = 4096;
char buffer[buffer_size];
// 读取文件并更新SHA-1计算
while (file) {
file.read(buffer, buffer_size);
absl::string_view data(buffer, static_cast<size_t>(file.gcount()));
sha1.Update(data);
}
// 获取SHA-1摘要
std::string sha1_digest = sha1.Hash();
// 输出SHA-1摘要
std::cout << "SHA-1 Digest: " << sha1_digest << std::endl;
// 关闭文件
file.close();
return 0;
}SIMD base64 encoder and decoder Example code and usage instructions can be found in the GitHub repository's README: modp_b64 GitHub Repository
base64编码
#include <stdio.h>
#include <modp_b64.h>
int main() {
const char* input_data = "Hello, World!"; // 要编码的数据
char output_data[128]; // 用于存储编码后的数据
// 进行Base64编码
size_t input_len = strlen(input_data);
size_t output_len = modp_b64_encode(output_data, input_data, input_len);
// 打印编码后的数据
printf("Base64 Encoded Data: %s\n", output_data);
printf("Encoded Data Length: %zu\n", output_len);
return 0;
}An open-source C++ library developed and used at Facebook Example code and documentation can be found on the folly GitHub repository: folly GitHub Repository
异步示例
#include <iostream>
#include <folly/futures/Future.h>
int main() {
// 创建一个Promise对象,用于产生Future
folly::Promise<int> promise;
folly::Future<int> future = promise.getFuture();
// 启动一个异步任务
std::thread asyncTask([&promise]() {
// 模拟异步操作
std::this_thread::sleep_for(std::chrono::seconds(2));
// 异步操作完成后,使用Promise设置Future的值
promise.setValue(42);
});
// 在主线程中等待Future完成
std::cout << "Waiting for the async task to complete..." << std::endl;
future.wait();
// 从Future中获取结果
int result = future.value();
// 打印结果
std::cout << "Async task result: " << result << std::endl;
// 等待异步任务完成
asyncTask.join();
return 0;
}Free peer-reviewed portable C++ source libraries Example code and extensive documentation can be found on the Boost website: Boost Documentation
进程间共享内存通信
#include <iostream>
#include <string>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/vector.hpp>
using namespace boost::interprocess;
int main() {
// 创建或打开共享内存
managed_shared_memory segment(open_or_create, "MySharedMemory", 65536);
// 创建一个可在共享内存中存储std::string的容器
typedef allocator<char, managed_shared_memory::segment_manager> CharAllocator;
typedef vector<std::string, CharAllocator> MyVector;
// 获取或创建vector对象
MyVector* myvector = segment.find_or_construct<MyVector>("MyVector")(segment.get_segment_manager());
// 向共享内存中的vector写入数据
myvector->push_back("Hello, shared memory!");
myvector->push_back("This is a message from the first process.");
// 等待一段时间,以便第二个进程有足够的时间来读取数据
std::this_thread::sleep_for(std::chrono::seconds(3));
return 0;
}#include <iostream>
#include <string>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/vector.hpp>
using namespace boost::interprocess;
int main() {
// 打开共享内存
managed_shared_memory segment(open_only, "MySharedMemory");
// 获取共享内存中的vector对象
typedef allocator<char, managed_shared_memory::segment_manager> CharAllocator;
typedef vector<std::string, CharAllocator> MyVector;
MyVector* myvector = segment.find<MyVector>("MyVector").first;
// 从共享内存中的vector读取数据并打印
for (const auto& str : *myvector) {
std::cout << str << std::endl;
}
return 0;
}Cross-platform asynchronous I/O Example code and documentation can be found on the libuv GitHub repository: libuv GitHub Repository
http client server通信
#include <uv.h>
#include <stdio.h>
void on_new_connection(uv_stream_t* server, int status) {
if (status < 0) {
fprintf(stderr, "New connection error: %s\n", uv_strerror(status));
return;
}
uv_tcp_t* client = (uv_tcp_t*)malloc(sizeof(uv_tcp_t));
uv_tcp_init(uv_default_loop(), client);
if (uv_accept(server, (uv_stream_t*)client) == 0) {
uv_read_start((uv_stream_t*)client,
[](uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
buf->base = (char*)malloc(suggested_size);
buf->len = suggested_size;
},
[](uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
if (nread > 0) {
printf("Received data from client: %.*s\n", (int)nread, buf->base);
}
else if (nread < 0) {
if (nread != UV_EOF) {
fprintf(stderr, "Read error: %s\n", uv_strerror(nread));
}
uv_close((uv_handle_t*)stream, [](uv_handle_t* handle) {
free(handle);
});
}
free(buf->base);
}
);
}
else {
uv_close((uv_handle_t*)client, [](uv_handle_t* handle) {
free(handle);
});
}
}
int main() {
uv_tcp_t server;
uv_loop_t* loop = uv_default_loop();
uv_tcp_init(loop, &server);
struct sockaddr_in bind_addr;
uv_ip4_addr("0.0.0.0", 8080, &bind_addr);
uv_tcp_bind(&server, (const struct sockaddr*)&bind_addr, 0);
int r = uv_listen((uv_stream_t*)&server, 128, on_new_connection);
if (r) {
fprintf(stderr, "Listen error: %s\n", uv_strerror(r));
return 1;
}
printf("HTTP server listening on port 8080...\n");
return uv_run(loop, UV_RUN_DEFAULT);
}
#include <uv.h>
#include <stdio.h>
void on_connect(uv_connect_t* req, int status) {
if (status < 0) {
fprintf(stderr, "Connection error: %s\n", uv_strerror(status));
return;
}
uv_stream_t* stream = req->handle;
uv_buf_t req_data = uv_buf_init("GET / HTTP/1.1\r\nHost: localhost\r\n\r\n", 29);
uv_write_t write_req;
uv_write(&write_req, stream, &req_data, 1, [](uv_write_t* req, int status) {
if (status < 0) {
fprintf(stderr, "Write error: %s\n", uv_strerror(status));
return;
}
uv_stream_t* stream = req->handle;
uv_read_start(stream,
[](uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
buf->base = (char*)malloc(suggested_size);
buf->len = suggested_size;
},
[](uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
if (nread > 0) {
printf("Received response: %.*s\n", (int)nread, buf->base);
}
else if (nread < 0) {
if (nread != UV_EOF) {
fprintf(stderr, "Read error: %s\n", uv_strerror(nread));
}
uv_close((uv_handle_t*)stream, [](uv_handle_t* handle) {
free(handle);
});
}
free(buf->base);
}
);
});
}
int main() {
uv_loop_t* loop = uv_default_loop();
uv_tcp_t client;
uv_tcp_init(loop, &client);
struct sockaddr_in server_addr;
uv_ip4_addr("127.0.0.1", 8080, &server_addr);
uv_connect_t connect_req;
uv_tcp_connect(&connect_req, &client, (const struct sockaddr*)&server_addr, on_connect);
printf("HTTP client connecting to localhost:8080...\n");
return uv_run(loop, UV_RUN_DEFAULT);
}
TLS/SSL and crypto library Example code and documentation can be found on the OpenSSL GitHub repository: OpenSSL GitHub Repository
ecdsa签名和验证
#include <stdio.h>
#include <string.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
#include <openssl/err.h>
int main() {
// 初始化 OpenSSL 库
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
// 创建 EC_KEY 对象
EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1);
if (!ec_key) {
fprintf(stderr, "Error creating EC_KEY\n");
return 1;
}
// 生成 EC_KEY 密钥对
if (EC_KEY_generate_key(ec_key) != 1) {
fprintf(stderr, "Error generating EC_KEY key pair\n");
return 1;
}
// 准备要签名的数据
const char *data_to_sign = "Hello, ECDSA!";
size_t data_len = strlen(data_to_sign);
// 计算数据的 SHA-256 哈希值
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256((const unsigned char *)data_to_sign, data_len, hash);
// 对数据进行签名
ECDSA_SIG *signature = ECDSA_do_sign(hash, sizeof(hash), ec_key);
if (!signature) {
fprintf(stderr, "Error signing data\n");
return 1;
}
// 打印签名结果
printf("ECDSA Signature:\n");
printf("R: %s\n", BN_bn2hex(signature->r));
printf("S: %s\n", BN_bn2hex(signature->s));
// 验证签名
int verification_result = ECDSA_do_verify(hash, sizeof(hash), signature, ec_key);
if (verification_result == 1) {
printf("Signature verification succeeded!\n");
} else if (verification_result == 0) {
printf("Signature verification failed!\n");
} else {
fprintf(stderr, "Error verifying signature\n");
}
// 释放资源
EC_KEY_free(ec_key);
ECDSA_SIG_free(signature);
ERR_free_strings();
return 0;
}
Dear ImGui: Bloat-free Graphical User Interface for C++ with minimal dependencies Example code and documentation can be found on the Dear ImGui GitHub repository: Dear ImGui GitHub Repository
#include "imgui.h"
// 定义一个结构来表示树形节点
struct TreeNode {
std::string name;
std::vector<TreeNode> children;
};
// 递归函数来绘制树形节点及其子节点
void DrawTreeNode(const TreeNode& node) {
bool node_open = ImGui::TreeNode(node.name.c_str());
// 处理节点的展开/折叠
if (node_open) {
for (const TreeNode& child : node.children) {
DrawTreeNode(child);
}
ImGui::TreePop();
}
// 处理双击事件
if (ImGui::IsItemClicked(0) && ImGui::IsMouseDoubleClicked(0)) {
// 在这里你可以添加双击节点后的操作,比如显示子节点的名称
// 在这个示例中,我们简单地打印子节点的名称
for (const TreeNode& child : node.children) {
ImGui::Text("Double-clicked child node: %s", child.name.c_str());
}
}
}
int main() {
// 初始化 ImGui
// 创建树形节点数据
TreeNode root;
root.name = "Root";
TreeNode child1;
child1.name = "Child 1";
TreeNode child2;
child2.name = "Child 2";
TreeNode grandchild1;
grandchild1.name = "Grandchild 1";
child1.children.push_back(grandchild1);
root.children.push_back(child1);
root.children.push_back(child2);
// 主循环
while (!glfwWindowShouldClose(window)) {
// 开始 ImGui 帧
// 绘制树形节点
DrawTreeNode(root);
// 结束 ImGui 帧
// 渲染 ImGui 内容
// ...
// 处理事件
// ...
}
// 清理 ImGui 资源
return 0;
}
Cross-platform, graphics API-agnostic rendering library Example code and documentation can be found on the bgfx GitHub repository: bgfx GitHub Repository
绘制旋转立方体
#include <bgfx/bgfx.h>
#include <bgfx/platform.h>
#include <bx/timer.h>
#include <bx/math.h>
#include <entry/entry.h>
namespace
{
const bgfx::VertexLayout PosColorVertex::ms_layout
= {bgfx::Attrib::Position, 3, bgfx::AttribType::Float, false, bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true};
bgfx::ProgramHandle loadProgram(const char* _vsName, const char* _fsName)
{
bgfx::ShaderHandle vsh = bgfx::createShader(loadShader(_vsName));
bgfx::ShaderHandle fsh = bgfx::createShader(loadShader(_fsName));
return bgfx::createProgram(vsh, fsh, true /* destroy shaders when program is destroyed */);
}
const bgfx::Memory* loadShader(const char* _name)
{
static std::map<std::string, std::unique_ptr<bgfx::Memory>> s_shaders;
auto it = s_shaders.find(_name);
if (it != s_shaders.end())
{
return it->second.get();
}
const std::string filePath = bx::strCat("shaders/", _name);
void* data = nullptr;
size_t size = 0;
bx::CrtFileReader reader;
bx::CrtFileReaderScope fileScope(&reader);
if (bx::open(&reader, filePath.c_str()) == 0)
{
size = bx::getSize(&reader);
data = BX_ALLOC(entry::getAllocator(), size);
bx::read(&reader, data, size);
}
bgfx::Memory* mem = bgfx::makeRef(data, (uint32_t)size, nullptr, [](void* _ptr, void* _userData) { BX_FREE(entry::getAllocator(), _ptr); });
s_shaders[_name] = std::unique_ptr<bgfx::Memory>(mem);
return mem;
}
const bgfx::Memory* s_cubeVertices;
const bgfx::Memory* s_cubeIndices;
bgfx::VertexBufferHandle s_vbh;
bgfx::IndexBufferHandle s_ibh;
bgfx::ProgramHandle s_program;
bgfx::UniformHandle s_time;
const bgfx::Memory* s_embeddedShaders[] = {
loadShader("vs_cubes.bin"), loadShader("fs_cubes.bin"),
};
}
int main(int argc, char** argv)
{
// 初始化 bgfx
bgfx::Init init;
init.type = bgfx::RendererType::Count;
bgfx::init(init);
bgfx::reset(init.width, init.height, BGFX_RESET_VSYNC);
bgfx::setDebug(BGFX_DEBUG_TEXT);
// 创建顶点和索引缓冲区
s_cubeVertices = bgfx::makeRef(cubeVertices, sizeof(cubeVertices));
s_cubeIndices = bgfx::makeRef(cubeIndices, sizeof(cubeIndices));
s_vbh = bgfx::createVertexBuffer(s_cubeVertices, PosColorVertex::ms_layout);
s_ibh = bgfx::createIndexBuffer(s_cubeIndices);
// 加载着色器程序
s_program = loadProgram("vs_cubes", "fs_cubes");
// 获取时间 uniform 句柄
s_time = bgfx::createUniform("u_time", bgfx::UniformType::Vec4);
// 主循环
while (!entry::processEvents(init.m_width, init.m_height, init.m_debug, init.m_reset, &init.m_exit))
{
float time = bx::getHPCounter() / double(bx::getHPFrequency());
float view[16];
float proj[16];
bx::mtxLookAt(view, {0.0f, 0.0f, -35.0f}, {0.0f, 0.0f, 0.0f});
bx::mtxProj(proj, 60.0f, float(init.m_width) / float(init.m_height), 0.1f, 100.0f, bgfx::getCaps()->homogeneousDepth);
// 设置渲染状态
bgfx::setViewRect(0, 0, 0, uint16_t(init.m_width), uint16_t(init.m_height));
bgfx::setViewTransform(0, view, proj);
bgfx::setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x303030ff, 1.0f, 0);
// 设置模型矩阵
float mtx[16];
bx::mtxRotateXY(mtx, time, time * 0.37f);
bgfx::setTransform(mtx);
// 绘制立方体
bgfx::setVertexBuffer(0, s_vbh);
bgfx::setIndexBuffer(s_ibh);
// 传递时间 uniform
bgfx::setUniform(s_time, &time);
// 提交绘制命令
bgfx::submit(0, s_program);
// 渲染帧
bgfx::frame();
}
// 清理资源
bgfx::destroy(s_time);
bgfx::destroy(s_ibh);
bgfx::destroy(s_vbh);
bgfx::destroy(s_program);
// 关闭 bgfx
bgfx::shutdown();
return 0;
}libplacebo is, in a nutshell, the core rendering algorithms and ideas of mpv rewritten as an independent library Example code and documentation can be found on the libplacebo GitHub repository: libplacebo GitHub Repository
颜色空间转换示例
#include <libplacebo/colorspace.h>
#include <libplacebo/renderer.h>
int main() {
// 初始化 libplacebo 上下文
pl_context *ctx = pl_context_create(NULL);
// 创建颜色空间转换上下文
pl_color_space *csp_ctx = pl_color_space_create(ctx, PL_COLOR_SPACE_AUTO);
// 设置源颜色空间和目标颜色空间
pl_color_space_params src_params = {PL_COLOR_SPACE_AUTO, PL_TRANSFER_AUTO, PL_PRIMARIES_AUTO};
pl_color_space_params dst_params = {PL_COLOR_SPACE_RGB, PL_TRANSFER_LINEAR, PL_PRIMARIES_REC709};
pl_color_space_select(csp_ctx, &src_params, &dst_params);
// 创建一个示例的 YUV 图像帧
// 实际情况下,你应该加载或生成你的图像帧数据
pl_image img = pl_image_create(ctx, PL_FMT_I420, width, height, NULL);
// 执行颜色空间转换
pl_color_space_convert(csp_ctx, &img, &img);
// 在这里你可以使用转换后的图像进行进一步处理或渲染
// 释放资源
pl_image_unref(&img);
pl_color_space_destroy(&csp_ctx);
pl_context_destroy(&ctx);
return 0;
}SPIRV-Cross is a practical tool and library for performing reflection on SPIR-V and disassembling SPIR-V back to high-level languages Example code and documentation can be found on the SPIRV-Cross GitHub repository: SPIRV-Cross GitHub Repository
着色器代码转换
#include <spirv_cross/spirv_cross.hpp>
int main() {
// 创建SPIRV-Cross的编译器对象
spirv_cross::Compiler compiler(spirv_data);
// 获取meta、D3D11和Vulkan着色器代码
std::string meta_shader = compiler.compile(spirv_cross::CompilerGLSL::Options());
std::string d3d11_shader = compiler.compile(spirv_cross::CompilerHLSL::Options());
std::string vulkan_shader = compiler.compile(spirv_cross::CompilerGLSL::Options());
// 现在你可以使用生成的着色器代码进行进一步处理或集成到你的应用程序中
return 0;
}A compact C++ cross-platform library including JSON, XML, HTTP, Sockets, WebSockets, threads, processes, logs, file system, CSV, INI files, etc Example code and documentation can be found on the asl GitHub repository: asl GitHub Repository
CmdArgs args(argc, argv);
int iterations = args["iterations"] | 10; // default to 10 if no parameter givenRead or write a configuration INI file ("config.ini" contains this):
[parameters]
threshold=0.25
IniFile config("config.ini");
float threshold = config["parameters/threshold"] | 0.2;
config["parameters/threshold"] = 0.5;Do HTTP requests (you can post a body or send headers, too):
HttpResponse resp = Http::get("https://www.somewhere.com/page.xhtml");
if(resp.code() != 200)
return -1;
String type = resp.header("Content-Type");
String text = resp.text();Or create HTTP services:
struct TimeServer : public HttpServer
{
void serve(HttpRequest& req, HttpResponse& resp)
{
if(req.is("GET", "/time")
{
resp.put(Var{{"time", Date::now().toString()}});
}
else
{
resp.put(Var{{"status", "error"}});
resp.setCode(500);
}
}
};
TimeServer server;
server.bind(80);
server.start();Decode XML:
Xml html = Xml::decode( "<html><head><meta charset='utf8'/></head></html>" );
String charset = html("head")("meta")["charset"]; // -> "utf8"
String rootTag = html.tag(); // -> "html"Read or write a file in one line:
String content = TextFile("somefile-uнicoδe.json").text();The path given above can be Unicode UTF8, and the file content can be UTF8 with or wothout BOM, UTF16-BE or UTF16-LE. And it will be converted to UTF8.
Emulate a simple wget:
File("image.png").put( Http::get("http://hello.com/image.png").body() );Decode JSON (but you can also directly load/save JSON from a file):
Var data = Json::decode(content);
String name = data["name"];
int number = data["age"];Write JSON:
Var particle = Var{
{"name", "proton"},
{"mass", 1.67e-27},
{"position", {x, y, z}}
};
String json = Json::encode(particle);Write to the console with colors:
Console console;
console.color(Console::BRED); // bright red text
console.bgcolor(Console::CYAN); // cyan background
printf("some highlighted text");Create threads (but you can also use lambdas):
class MyThread : public Thread
{
void run() { do_stuff(); }
};
MyThread thread;
thread.start();Send data through a TCP socket (that will try different hosts if DNS "host" maps to several IPv4 or IPv6 addresses):
Socket socket; // or TlsSocket for SSL/TLS
socket.connect("host", 9000);
socket << "hello\n";Or a message through a WebSocket:
WebSocket socket;
socket.connect("host", 9000); // or "ws://host:9000"
socket.send("hello");Strings are 8 bit, by default assumed to be UTF8, and can be case converted even beyond ASCII:
String country = "Ελλάδα";
String upper = country.toUpperCase(); // -> "ΕΛΛΆΔΑ"Strings have some additional handy methods:
if(filename.startsWith(prefix) || filename.contains("-"))A string can be split and joined back:
String names = "one,two,three";
Array<String> numbers = names.split(",");
String s123 = numbers.join(" "); // -> "one two three"and can be automatically converted to UTF16:
String dirname = "newdir";
CreateDirectoryW( dirname ); // autoconverted to UTF16But don't use the above Windows-only function when you can (in UTF8):
Directory::create("newdir");or enumerate the contents of a directory:
Directory dir("some/dir");
for(File& file : dir.files("*.txt"))
{
String path = file.path();
Long size = file.size();
Date date = file.lastModified();
}Copy, move or delete files:
File("letter.doc").copy("/backup/");
File("file.conf").move("file.ini");
File("trash.doc").remove();
Directory::remove("/trash/"); // must be emptyStart a subprocess and read its output:
Process p = Process::execute("someprogram.exe");
if(p.success())
output = p.output();Get the parent directory, file name and extension of a path:
Path path = "/some/dir/file.txt";
path.directory() // -> "/some/dir/"
path.name() // -> "file.txt"
path.nameNoExt() // -> "file"
path.extension() // -> "txt"Time an operation with precision (around microseconds) and sleep for some time:
double t1 = now();
sleep(0.5); // 0.5 seconds
double t2 = now();
double elapsed = t2 - t1; // should be around 0.5Log a message to the console and to a file:
ASL_LOG_W("Only %i bytes available", bytesAvailable);STXXL: Standard Template Library for Extra Large Data Sets Example code and documentation can be found on the stxxl GitHub repository: stxxl GitHub Repository
操作大于内存的vector
#include <iostream>
#include <stxxl/sort>
#include <stxxl/vector>
int main() {
// Define a vector with external memory support
stxxl::vector<int> data_vector;
// Fill the vector with some data (this data may not fit in RAM)
for (int i = 1000000; i > 0; --i) {
data_vector.push_back(i);
}
// Define a comparator for sorting
struct IntComparator {
bool operator()(const int& a, const int& b) const {
return a < b;
}
};
// Sort the data using external sorting
stxxl::sort(data_vector.begin(), data_vector.end(), IntComparator(), 1024 * 1024 * 64); // 64MB of RAM for sorting
// Print the sorted data
for (const int& value : data_vector) {
std::cout << value << " ";
}
return 0;
}