实现jpeg编码。
This commit is contained in:
parent
c48c31c316
commit
a865f749be
@ -2,6 +2,7 @@
|
|||||||
#include "BoostLog.h"
|
#include "BoostLog.h"
|
||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
#include "H264Palyer.h"
|
#include "H264Palyer.h"
|
||||||
|
#include "Settings.h"
|
||||||
#include "VideoFrameProvider.h"
|
#include "VideoFrameProvider.h"
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QFont>
|
#include <QFont>
|
||||||
@ -9,10 +10,31 @@
|
|||||||
#include <QQmlApplicationEngine>
|
#include <QQmlApplicationEngine>
|
||||||
#include <QQmlContext>
|
#include <QQmlContext>
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &os, const ImageFormat &format) {
|
||||||
|
switch (format) {
|
||||||
|
case ImageFormat::Jpeg:
|
||||||
|
os << "Jpeg";
|
||||||
|
break;
|
||||||
|
case ImageFormat::YUV:
|
||||||
|
os << "YUV";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
os << "Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
Application::Application(int &argc, char **argv)
|
Application::Application(int &argc, char **argv)
|
||||||
: m_app(std::make_shared<QGuiApplication>(argc, argv)), m_videoFrameProvider(new VideoFrameProvider()),
|
: m_app(std::make_shared<QGuiApplication>(argc, argv)), m_videoFrameProvider(new VideoFrameProvider()),
|
||||||
m_player(std::make_shared<H264Palyer>()), m_devices(new DeviceListModel(this)),
|
m_player(std::make_shared<H264Palyer>()), m_devices(new DeviceListModel(this)),
|
||||||
m_collector(new DataCollection(this)) {
|
m_collector(new DataCollection(this)) {
|
||||||
|
using namespace Amass;
|
||||||
|
|
||||||
|
m_settings = Singleton<Settings>::instance<Construct>();
|
||||||
|
m_settings->load();
|
||||||
|
m_collector->setImageFormat(m_settings->imageFormat(), m_settings->imageQuality());
|
||||||
|
|
||||||
QFont font;
|
QFont font;
|
||||||
font.setPointSize(16);
|
font.setPointSize(16);
|
||||||
font.setFamily("微软雅黑");
|
font.setFamily("微软雅黑");
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
class QGuiApplication;
|
class QGuiApplication;
|
||||||
class VideoFrameProvider;
|
class VideoFrameProvider;
|
||||||
|
class Settings;
|
||||||
class H264Palyer;
|
class H264Palyer;
|
||||||
|
|
||||||
class Application : public QObject {
|
class Application : public QObject {
|
||||||
@ -102,6 +103,7 @@ protected:
|
|||||||
private:
|
private:
|
||||||
std::shared_ptr<QGuiApplication> m_app;
|
std::shared_ptr<QGuiApplication> m_app;
|
||||||
VideoFrameProvider *m_videoFrameProvider = nullptr;
|
VideoFrameProvider *m_videoFrameProvider = nullptr;
|
||||||
|
std::shared_ptr<Settings> m_settings;
|
||||||
std::shared_ptr<H264Palyer> m_player;
|
std::shared_ptr<H264Palyer> m_player;
|
||||||
std::weak_ptr<DeviceConnection> m_device;
|
std::weak_ptr<DeviceConnection> m_device;
|
||||||
DeviceListModel *m_devices = nullptr;
|
DeviceListModel *m_devices = nullptr;
|
||||||
|
@ -52,6 +52,7 @@ add_executable(AntiClipSettings
|
|||||||
DeviceListModel.h DeviceListModel.cpp
|
DeviceListModel.h DeviceListModel.cpp
|
||||||
H264Palyer.h H264Palyer.cpp
|
H264Palyer.h H264Palyer.cpp
|
||||||
VideoFrameProvider.h VideoFrameProvider.cpp
|
VideoFrameProvider.h VideoFrameProvider.cpp
|
||||||
|
Settings.h Settings.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (Qt6_FOUND)
|
if (Qt6_FOUND)
|
||||||
@ -92,10 +93,12 @@ add_subdirectory(${Projects_ROOT}/Kylin/Encrypt Encrypt)
|
|||||||
target_include_directories(AntiClipSettings
|
target_include_directories(AntiClipSettings
|
||||||
PRIVATE ${FFmpeg_INCLUDE_DIR}
|
PRIVATE ${FFmpeg_INCLUDE_DIR}
|
||||||
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
|
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
PRIVATE ${Libraries_ROOT}/libjpeg-turbo64/include
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_directories(AntiClipSettings
|
target_link_directories(AntiClipSettings
|
||||||
PRIVATE ${FFmpeg_LIB_DIR}
|
PRIVATE ${FFmpeg_LIB_DIR}
|
||||||
|
PRIVATE ${Libraries_ROOT}/libjpeg-turbo64/lib
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(AntiClipSettings
|
target_link_libraries(AntiClipSettings
|
||||||
@ -111,6 +114,7 @@ target_link_libraries(AntiClipSettings
|
|||||||
PRIVATE avformat
|
PRIVATE avformat
|
||||||
PRIVATE Universal
|
PRIVATE Universal
|
||||||
PRIVATE Encrypt
|
PRIVATE Encrypt
|
||||||
|
PRIVATE turbojpeg-static
|
||||||
PRIVATE Ws2_32
|
PRIVATE Ws2_32
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <boost/json/object.hpp>
|
#include <boost/json/object.hpp>
|
||||||
#include <boost/json/parse.hpp>
|
#include <boost/json/parse.hpp>
|
||||||
#include <boost/json/serialize.hpp>
|
#include <boost/json/serialize.hpp>
|
||||||
|
#include <turbojpeg.h>
|
||||||
|
|
||||||
DataCollection::DataCollection(QObject *parent) : QObject{parent} {
|
DataCollection::DataCollection(QObject *parent) : QObject{parent} {
|
||||||
m_manager = new QNetworkAccessManager(this);
|
m_manager = new QNetworkAccessManager(this);
|
||||||
@ -24,6 +25,15 @@ void DataCollection::stop() {
|
|||||||
emit enabledChanged();
|
emit enabledChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DataCollection::setImageFormat(ImageFormat format, int quality) {
|
||||||
|
if (m_format != format) {
|
||||||
|
m_format = format;
|
||||||
|
}
|
||||||
|
if (m_quality != quality) {
|
||||||
|
m_quality = quality;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString DataCollection::path() const {
|
QString DataCollection::path() const {
|
||||||
return m_path;
|
return m_path;
|
||||||
}
|
}
|
||||||
@ -78,13 +88,81 @@ void DataCollection::onCaptureFinished() {
|
|||||||
void DataCollection::onDataGetFinished() {
|
void DataCollection::onDataGetFinished() {
|
||||||
auto reply = dynamic_cast<QNetworkReply *>(sender());
|
auto reply = dynamic_cast<QNetworkReply *>(sender());
|
||||||
auto data = reply->readAll();
|
auto data = reply->readAll();
|
||||||
LOG(info) << "error: " << reply->error() << ", capture data size: " << data.size();
|
if (m_format == ImageFormat::Jpeg) {
|
||||||
|
m_filename.replace("yuv", "jpg");
|
||||||
|
}
|
||||||
|
LOG(info) << "filename: " << m_filename.toStdString() << ", error: " << reply->error()
|
||||||
|
<< ", capture data size: " << data.size();
|
||||||
QFile file(m_path + "/" + m_filename);
|
QFile file(m_path + "/" + m_filename);
|
||||||
file.open(QIODevice::WriteOnly);
|
file.open(QIODevice::WriteOnly);
|
||||||
file.write(data);
|
if (m_format == ImageFormat::Jpeg) {
|
||||||
|
auto jpegBuffer =
|
||||||
|
encodeNv21ToJpeg(reinterpret_cast<uint8_t *>(data.data()), ImageWidth, ImageHeight, m_quality);
|
||||||
|
file.write(reinterpret_cast<const char *>(jpegBuffer.data()), jpegBuffer.size());
|
||||||
|
} else {
|
||||||
|
file.write(data);
|
||||||
|
}
|
||||||
file.close();
|
file.close();
|
||||||
if (m_enabled) {
|
if (m_enabled) {
|
||||||
QTimer::singleShot(0, this, [this]() { start(); });
|
QTimer::singleShot(0, this, [this]() { start(); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void convertNV21ToYUV420(uint8_t *nv21, uint8_t *yuv420, int width, int height) {
|
||||||
|
int frameSize = width * height;
|
||||||
|
int chromaSize = frameSize / 4;
|
||||||
|
|
||||||
|
memcpy(yuv420, nv21, frameSize);
|
||||||
|
|
||||||
|
uint8_t *u = yuv420 + frameSize;
|
||||||
|
uint8_t *v = u + chromaSize;
|
||||||
|
|
||||||
|
uint8_t *uv = nv21 + frameSize;
|
||||||
|
|
||||||
|
for (int i = 0; i < chromaSize; i++) {
|
||||||
|
u[i] = uv[2 * i + 1];
|
||||||
|
v[i] = uv[2 * i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> DataCollection::encodeNv21ToJpeg(uint8_t *nv21, int width, int height, int quality) {
|
||||||
|
tjhandle handle = tjInitCompress();
|
||||||
|
if (handle == nullptr) {
|
||||||
|
fprintf(stderr, "Failed to initialize turbojpeg compressor\n");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long jpeg_size = 0;
|
||||||
|
uint8_t *jpeg_buffer = nullptr;
|
||||||
|
|
||||||
|
int yuv_size = tjBufSizeYUV2(width, 4, height, TJSAMP_420);
|
||||||
|
uint8_t *yuv_buffer = (uint8_t *)malloc(yuv_size);
|
||||||
|
if (yuv_buffer == nullptr) {
|
||||||
|
fprintf(stderr, "Failed to allocate YUV buffer\n");
|
||||||
|
tjDestroy(handle);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert NV21 to YUV420
|
||||||
|
convertNV21ToYUV420(nv21, yuv_buffer, width, height);
|
||||||
|
|
||||||
|
// Compress YUV to JPEG
|
||||||
|
int retval = tjCompressFromYUV(handle, yuv_buffer, width, 4, height, TJSAMP_420, &jpeg_buffer, &jpeg_size, quality,
|
||||||
|
TJFLAG_FASTDCT);
|
||||||
|
if (retval != 0) {
|
||||||
|
fprintf(stderr, "Failed to compress to JPEG: %s\n", tjGetErrorStr());
|
||||||
|
free(yuv_buffer);
|
||||||
|
tjDestroy(handle);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the JPEG buffer into a std::vector
|
||||||
|
std::vector<uint8_t> jpeg_vector(jpeg_buffer, jpeg_buffer + jpeg_size);
|
||||||
|
|
||||||
|
// Free the JPEG buffer allocated by libjpeg-turbo
|
||||||
|
tjFree(jpeg_buffer);
|
||||||
|
free(yuv_buffer);
|
||||||
|
tjDestroy(handle);
|
||||||
|
|
||||||
|
return jpeg_vector;
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#ifndef DATACOLLECTION_H
|
#ifndef DATACOLLECTION_H
|
||||||
#define DATACOLLECTION_H
|
#define DATACOLLECTION_H
|
||||||
|
|
||||||
|
#include "DataStructure.h"
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
|
|
||||||
@ -17,6 +18,7 @@ public:
|
|||||||
explicit DataCollection(QObject *parent = nullptr);
|
explicit DataCollection(QObject *parent = nullptr);
|
||||||
Q_INVOKABLE void start(const QString &address);
|
Q_INVOKABLE void start(const QString &address);
|
||||||
Q_INVOKABLE void stop();
|
Q_INVOKABLE void stop();
|
||||||
|
void setImageFormat(ImageFormat format, int quality);
|
||||||
|
|
||||||
QString path() const;
|
QString path() const;
|
||||||
void setPath(const QString &path);
|
void setPath(const QString &path);
|
||||||
@ -31,6 +33,7 @@ protected:
|
|||||||
void start();
|
void start();
|
||||||
void onCaptureFinished();
|
void onCaptureFinished();
|
||||||
void onDataGetFinished();
|
void onDataGetFinished();
|
||||||
|
static std::vector<uint8_t> encodeNv21ToJpeg(uint8_t *nv21, int width, int height, int quality);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QNetworkAccessManager *m_manager = nullptr;
|
QNetworkAccessManager *m_manager = nullptr;
|
||||||
@ -38,6 +41,9 @@ private:
|
|||||||
QString m_address;
|
QString m_address;
|
||||||
QString m_path;
|
QString m_path;
|
||||||
QString m_filename;
|
QString m_filename;
|
||||||
|
|
||||||
|
ImageFormat m_format = ImageFormat::Jpeg;
|
||||||
|
int m_quality = 100;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DATACOLLECTION_H
|
#endif // DATACOLLECTION_H
|
||||||
|
@ -4,6 +4,15 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
|
|
||||||
|
constexpr int ImageWidth = 576;
|
||||||
|
constexpr int ImageHeight = 320;
|
||||||
|
enum class ImageFormat : int {
|
||||||
|
Jpeg = 0,
|
||||||
|
YUV, // nv21 576x320
|
||||||
|
None, // 新增枚举需要放在这上面
|
||||||
|
};
|
||||||
|
std::ostream &operator<<(std::ostream &os, const ImageFormat &format);
|
||||||
|
|
||||||
struct NetworkInfomation {
|
struct NetworkInfomation {
|
||||||
Q_GADGET
|
Q_GADGET
|
||||||
QML_NAMED_ELEMENT(networkInfomation)
|
QML_NAMED_ELEMENT(networkInfomation)
|
||||||
|
50
Settings.cpp
Normal file
50
Settings.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include "Settings.h"
|
||||||
|
#include "BoostLog.h"
|
||||||
|
#include <boost/property_tree/ptree.hpp>
|
||||||
|
#include <boost/property_tree/xml_parser.hpp>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
constexpr auto SettingsFilePath = "settings.xml";
|
||||||
|
|
||||||
|
Settings::Settings() {
|
||||||
|
if (!std::filesystem::exists(SettingsFilePath)) {
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::save() {
|
||||||
|
boost::property_tree::ptree ptree;
|
||||||
|
ptree.put("Application.DataCollection.ImageFormat", static_cast<int>(m_imageFormat));
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
for (int i = 0; i < static_cast<int>(ImageFormat::None); i++) {
|
||||||
|
oss << i << ":" << static_cast<ImageFormat>(i) << " ";
|
||||||
|
}
|
||||||
|
ptree.put("Application.DataCollection.ImageFormat.<xmlcomment>", oss.str());
|
||||||
|
|
||||||
|
ptree.put("Application.DataCollection.ImageQuality", m_imageQuality);
|
||||||
|
ptree.put("Application.DataCollection.ImageQuality.<xmlcomment>", "0-100,仅对jpg有效");
|
||||||
|
|
||||||
|
boost::property_tree::xml_writer_settings<std::string> settings('\t', 1);
|
||||||
|
boost::property_tree::write_xml(SettingsFilePath, ptree, std::locale(), settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::load() {
|
||||||
|
boost::property_tree::ptree ptree;
|
||||||
|
try {
|
||||||
|
boost::property_tree::read_xml(SettingsFilePath, ptree);
|
||||||
|
m_imageFormat = static_cast<ImageFormat>(ptree.get<int>("Application.DataCollection.ImageFormat"));
|
||||||
|
m_imageQuality = ptree.get<int>("Application.DataCollection.ImageQuality");
|
||||||
|
} catch (...) {
|
||||||
|
LOG(error) << "parse " << SettingsFilePath << " failed.";
|
||||||
|
}
|
||||||
|
LOG(info) << "image format: " << m_imageFormat << ", quality: " << m_imageQuality;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageFormat Settings::imageFormat() const {
|
||||||
|
return m_imageFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Settings::imageQuality() const {
|
||||||
|
return m_imageQuality;
|
||||||
|
}
|
24
Settings.h
Normal file
24
Settings.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef SETTINGS_H
|
||||||
|
#define SETTINGS_H
|
||||||
|
|
||||||
|
#include "DataStructure.h"
|
||||||
|
#include "Singleton.h"
|
||||||
|
|
||||||
|
class Settings {
|
||||||
|
friend class Amass::Singleton<Settings>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void save();
|
||||||
|
void load();
|
||||||
|
ImageFormat imageFormat() const;
|
||||||
|
int imageQuality() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Settings();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ImageFormat m_imageFormat = ImageFormat::Jpeg; // 0: jpg 1: yuv
|
||||||
|
int m_imageQuality = 100;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SETTINGS_H
|
Loading…
Reference in New Issue
Block a user