-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathjp2writer.cpp
More file actions
125 lines (109 loc) · 3.7 KB
/
jp2writer.cpp
File metadata and controls
125 lines (109 loc) · 3.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include "jp2writer.h"
#include <QDebug>
#include <QFile>
#include <vector>
#include <execution>
#include "scopedresource.h"
#include <openjpeg.h>
bool Jp2Writer::save(AVFrame *frm, QString fileName, std::future<void> &metaDataReady, QString &iccFileName,
ColorParams &colr, ExifData &exifData)
{
std::vector<opj_image_cmptparm_t> cmptparm;
opj_cparameters_t encParams;
OPJ_COLOR_SPACE cSpace;
int compts;
if (frm->format == AV_PIX_FMT_YUVJ420P || frm->format == AV_PIX_FMT_YUV420P) {
opj_image_cmptparm_t comp {
.dx = 0, .dy = 0,
.w = OPJ_UINT32(frm->width), .h = OPJ_UINT32(frm->height),
.x0 = 0, .y0 = 0,
.prec = 8,
.bpp = 8,
.sgnd = 0
};
cmptparm.push_back(comp); // Y
comp.w = frm->linesize[1];
comp.h = (frm->height + 1) / 2;
cmptparm.push_back(comp); // Cb
cmptparm.push_back(comp); // Cr
cSpace = OPJ_CLRSPC_SYCC;
compts = 3;
}
else {
qCritical() << "unsupported frame format" << frm->format;
return false;
}
ScopedResource<opj_image, bool> img(
[&] (opj_image *&img, bool &err) {
img = opj_image_create(cmptparm.size(), cmptparm.data(), cSpace);
err = img == nullptr;
},
[](opj_image *img, const bool &err) {
if (!err)
opj_image_destroy(img);
});
auto jp2 = img.get();
if (jp2 == nullptr) {
qCritical() << "error creating JP2 image";
return false;
}
jp2->x0 = jp2->y0 = 0;
jp2->x1 = frm->width;
jp2->y1 = frm->height;
ScopedResource<opj_codec_t, bool> codec(
[&] (opj_codec_t *&codec, bool &err) {
codec = opj_create_compress(OPJ_CODEC_JP2);
err = codec == nullptr;
},
[](opj_codec_t *codec, const bool &err) {
if (!err)
opj_destroy_codec(codec);
});
if (codec.error()) {
qCritical() << "error creating JP2 codec";
return false;
}
opj_set_default_encoder_parameters(&encParams);
if (!opj_setup_encoder(codec.get(), &encParams, jp2)) {
qCritical() << "error setting up JP2 encoder";
return false;
}
opj_codec_set_threads(codec.get(), opj_get_num_cpus());
{
ScopedResource<opj_stream_t, bool> strm(
[&] (opj_stream_t *&strm, bool &err) {
strm = opj_stream_create_default_file_stream(fileName.toLocal8Bit(), false);
err = strm == nullptr;
},
[](opj_codec_t *strm, const bool &err) {
if (!err)
opj_stream_destroy(strm);
});
if (strm.error()) {
qCritical() << "error creating JP2 output stream";
return false;
}
for (int i = 0; i < compts; i++) {
std::copy(std::execution::par_unseq,
frm->data[i], frm->data[i] + frm->linesize[i] * jp2->comps[i].h + 1, jp2->comps[i].data);
}
if (!opj_start_compress(codec.get(), jp2, strm.get()) ||
!opj_encode(codec.get(), strm.get()) ||
!opj_end_compress(codec.get(), strm.get())) {
qCritical() << "error running JP2 encoder";
return false;
}
}
// metadata
auto exiv2 = ExifImage(fileName.toStdString());
metaDataReady.wait();
exiv2.setExifData(exifData);
if (!iccFileName.isEmpty()) {
QFile file(iccFileName);
file.open(QIODevice::ReadOnly);
auto ba = file.readAll();
exiv2.setIccProfile(reinterpret_cast<const uint8_t *>(ba.data()), ba.length());
}
exiv2.writeMetadata();
return true;
}